JavaScript 有哪些資料型別 (data types)? 該怎麼辨別一個變數的資料型別?
2023年8月21日
如同絕大多數的程式語言,JavaScript 有其內建的資料型別。其中又有分原生值 (primitive values) 以及物件 (objects)。你知道在 JavaScript 當中有哪些是原生值? 哪些是物件? 又可以透過什麼樣的方法來辨別某個變數是什麼型別呢? 讓我們一起來看看這題面試常出現的基礎題吧!
JavaScript 的原生值 (primitive values)
截至目前,JavaScript 的資料型別中,有七個原生值。這七個原生值以外的,全都是屬於物件。
原生值是不可變的 (immutable),意思是我們不能改變那個值本身。舉例來說字串 (string) 是其中一個 JavaScript 原生值,我們不能去改變 'Hi'
這一個字串 (但在其他程式語言,字串有可能是可變的,例如在 C 就是可變的)。我們僅可以把某個變數,賦予另一個字串,例如:
let greeting = "Hi";
greeting = "Hello"; // 賦予另一個值,但上面的 'Hi' 本身沒變動
JavaScript 的型別中的七個原生值包含
String (字串)
字串是最常見的原生值之一。如前面提到,在 JavaScript 當中字串本身是不可變的。當我們用 substring()
來擷取字串,或用 concat()
來把兩個字串合為一,這些都是會回傳另一個字串,而非改變原本的字串。
Boolean (布林值)
有 true
與 false
兩個值的布林值,也是 JavaScript 的原生值。
Number
JavaScript 與一些語言不同,沒有分整數與浮點數,而是都用 number
這個原生值。不論整數或浮點數,都是 number
這個型別。在 JavaScript 當中,+Infinity
, -Infinity
, 與 NaN 都是 number
這個型別,所以我們用 typeof
來檢查的話,會得到 number
。
console.log(typeof NaN); // number
而 number
在 JavaScript 是雙精度浮點數,所以精確度是介於 -(2^53 − 1)
與 2^53 − 1
之間。在這個範圍之外,就會有精準度的問題,這時候要用另一個原生值 BigInt
。
BigInt
上面提到在 JavaScript 的整數與浮點數,都是用 number
這個型別,這其實只說了一半。因為 JavaScript 的 number
精準度有其限制,雖然多數情況很夠用 (2^53 - 1
會是 9007199254740991,我們很少用到比這大的數)。但有些時候會需要更往下的精準度。這時就可以用 BigInt
數值的型別。
BigInt
可以讓我們任意選擇其精準度,就可以避免一些 number
會遇到的問題。它跟 number
一樣可以用 +
, *
, -
, **
, 與 %
等運算子,不過要注意不可以拿 BigInt
跟 number
型別的值交互使用,這會出現 TypeError
。
Undefined
undefined
是一個型別,它本身也是一個值。假如某個變數還沒被宣告,我們就先使用,在 JavaScript 會出現索引錯誤 ReferenceError
(如果是用 let
與 const
來宣告該變數)。但如果是宣告了,但沒有賦予某個值,這時因為對 JavaScript 來說,它不知道該變數的值是什麼,所以會印出 undefined
。
// 還沒宣告就使用,會有 `ReferenceError`
console.log(greeting); // Uncaught ReferenceError: greeting is not defined
let greeting;
// 宣告了但還沒賦值,會是 `undefined`
let greeting;
console.log(greeting); // undefined
Null
null
是很容易跟 undefined
搞混的原生值。undefined
是因為某變數還沒有賦值,所以對 JavaScript 來說,它不知道該變數的值是什麼,所以要讀取該變數時,會是 undefined
。不過 null
則是我們賦予某個變數 null
這一個值。
Symbol
最後一個 JavaScript 原生值是 Symbol
,它是一個獨特 (unique) 值,多半會搭配物件一起使用,作為物件的鍵 (key)。
const sym = Symbol("ExplainThis");
const obj = { [sym]: "Interview Preps for Software Engineers" };
obj[sym]; // Interview Preps for Software Engineers
JavaScript 的物件 (objects)
除了上述的七個原生值以外的存在,在 JavaScript 當中都是物件。在 JavaScript 有一個梗是
Objects, Arrays, Functions, Objects 當中,Objects 好像被重複提了兩次。喔不,其實是四次。
會說 Objects 被提了四次說因為在 JavaScript 當中,Array (陣列) 與 Function (函式),都是物件。
如何辨別一個變數的資料型別?
要辨別一個變數的資料型別,最常見的方式是透過 typeof
這個方法。舉例來說 typeof
判斷字串。
let greeting = "hi";
console.log(typeof greeting); // 'string'
不過在 JavaScript 當中,有幾個小例外,其中一個是 null
。如果用 typeof
判斷 null
的資料型別,會得到 object
。
console.log(typeof null); // object
這是一個 JavaScript 的歷史遺跡,但因為要改掉這個 bug 的成本太高,所以到目前為止還是有這個錯誤。
不論如何, null
的資料型別應該是 null
而不是 object。
另一點要注意的是,typeof
判斷陣列時,會回傳 object
; 但判斷函式時,會回傳 function
。
console.log(typeof []); // object
console.log(typeof function () {}); // function
補充 typeof
結果的表格,來源參考 ECMAScript® 2015 Language Specification 。
Type of val | Result |
---|---|
Undefined | "undefined" |
Null | "object" |
Boolean | "boolean" |
Number | "number" |
String | "string" |
Object (native and does not implement [[Call]]) | "object" |
Object (native or host and does implement [[Call]]) | "function" |
Object (host and does not implement [[Call]]) | Implementation-defined except may not be "undefined", "boolean", "number", or "string". |
我們該如何辨別某個變數是物件,還是陣列呢?
Array.isArray()
是可以協助我們的方法。如果是陣列,會回傳 true
;但若是一般物件,則會回傳 false
。舉例來說:
Array.isArray([1, 2, 3]); // true
Array.isArray({ foo: 123 }); // false
我們也可以透過 Object.prototype.toString()
的方法幫助我們辨別陣列、函式與一般物件。
const arr = [1, 2, 3];
const fn = () => {
return 123;
};
const obj = { foo: 123 };
console.log(Object.prototype.toString.call(arr)); // [object Array]
console.log(Object.prototype.toString.call(fn)); // [object Function]
console.log(Object.prototype.toString.call(obj)); // [object Object]