JavaScript 資料型別

JavaScript 資料型別有七種,又分為原始型別物件型別

介紹

原始型別有六種:

  • Boolean 布林,例如:true、false
  • Null 空值
  • Undefined 未定義
  • Number 數字,例如:12345
  • String 字串,例如:'Hello World'
  • Symbol(ES2015 新增) 符號

其他的都是物件型別:

  • Object 物件,包含(物件 Object、陣列 Array、函式 Function、時間 Date…)

辨別方式

可以透過 typeof 來辨別型別

1
2
3
4
5
6
7
8
9
10
11
12
13
console.log(typeof 1); // number
console.log(typeof "2"); // string
console.log(typeof true); // boolean
console.log(typeof { a: 1 }); // object
console.log(typeof [1, 2]); // object
console.log(typeof new Date()); // object
console.log(typeof undefined); // undefined
console.log(typeof blabla); // undefined,因為是個 undefined 變數

// 以下是比較特別的案例
console.log(typeof NaN); //number
console.log(typeof function () {}); // function
console.log(typeof null); // object

註:typeof null 是一個在 JavaScript 剛推出時就存在的 bug,因為擔心改動後會導致太多網站壞掉,所以目前及未來都沒有改的計畫。

仔細看會發現,確實像是時間、陣列都會被辨別為物件,雖然畢竟當初分類就是這麼分的,但在實務使用上還是有點不方便,因此其實有其他方式可以更準確地達到實務上的需求 ─ Object.prototype.toString.call(...)

1
2
3
4
5
6
7
8
9
// 看後面可以知道確切格式
console.log(Object.prototype.toString.call(null)); // [Object Null]
console.log(Object.prototype.toString.call([1, 2])); // [Object Array]
console.log(Object.prototype.toString.call(new Date())); // [Object Date]

// 凡事都有例外
console.log(Object.prototype.toString.call(NaN)); // [Object Number]
// 想要驗證 NAN,isNaN() 是唯一解
console.log(isNaN(NaN)); // true

原始型別 VS 物件型別

可否更改原值

原始型別只能重新賦值,不能更改原值,比方說

1
2
3
4
5
6
7
let str = "aa";
str.toUpperCase(); // 將字串變大寫
console.log(str); // 還是 aa,因為字串是原始型別不能更改

let str = "aa";
str = str.toUpperCase(); // 將自串變大寫的值賦值到變數中
console.log(str); // 重新賦值後就會變 AA

物件型別可以更改原值,比方說

1
2
3
let arr = ["a", "b"];
arr.push("c"); // 在陣列中加入 'c'
console.log(arr); // ["a", "b", "c"],原本的 arr 會直接更改

變數存放方式

之所以會有這樣的差別,最大的差別就在於變數存放的方式。可以想像成變數名稱都是一張 memo 紙,而變數是一個箱子。

在原始型別當中,寫著變數名稱的 memo 紙貼著的箱子裡,放的就是變數的值,但在物件型別當中,寫著變數名稱的 memo 紙貼著的箱子裡,放的是一個記憶體位置,記憶體位置中放的才是變數的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let str = "aa"; // 'aa' 真的放在 str 貼著的箱子裡
let arr = ["a", "b"]; // arr 貼著的箱子裡放的是記憶體位置 0x01,0x01 裡放的才是 ['a', 'b']

let str = 1;
let str1 = 1;
console.log(str === str1); // true

let arr = [1, 2]; // 變數內存著記憶體位置 0x01
let arr1 = [1, 2]; // 變數內存著記憶體位置 0x02
console.log(arr === arr1); // false,因為記憶體位置不同

let arr = [1, 2];
let arr1 = arr; // arr 把記憶體位置分享給 arr1,目前兩個變數都存著一樣的記憶體位置
console.log(arr === arr1); // true

// 因此在更改物件型別值的時候要注意
let arr = [1, 2];
let arr1 = arr;
arr1.push(3); // 因為指向同個記憶體位置,當更改 arr1 時 arr 也會被改到
console.log(arr); // [1, 2, 3]
console.log(arr1); // [1, 2, 3]

// 原始型別
let str = "aa";
let str1 = str;
str1.toUpperCase();
console.log(str); // 'aa'
console.log(str1); // 'aa',因為前面有說原始型別不能直接更改只能重新賦值

let str = "aa";
let str1 = str;
str1 = str1.toUpperCase(); // 重新賦值
console.log(str); // 'aa'
console.log(str1); // 'AA',重新賦值後更改了,但不影響其他變數

綜合以上,我們會稱 ==物件型別是可變的 mutable,原始型別是不可變的 immutable==。

= 與 == 與 ===

  • =:賦值
  • ==:兩邊進行比較,且會自動進行型別轉換
  • ===:兩邊進行比較,但不進行型別轉換
1
2
3
4
5
6
7
8
9
10
11
let a = 1;
console.log(a == "1"); // true
console.log(a === "1"); // false

if ((a = 2)) {
// 這邊會賦值
console.log("a = 2");
} else {
console.log("a = 1");
}
// 印出 'a = 2'

因此在比較時,永遠都是用 === 最可靠。關於更多的 ===== 比較可參考這個 好懂表格

另外,NaN 不大於、小於、等於任何數字或是 NaNNaN 與任何數字運算也都會變成 NaN

評論

無法加載 Disqus 評論系統,請確保您的網絡能夠正常訪問。