JavaScript 有哪些資料型別 (data types)? 該怎麼辨別一個變數的資料型別?

2023年8月21日

💎 加入 E+ 成長計畫 與超過 250+ 位軟體工程師一起在社群中成長,並且獲得更深入、系統性軟體工程內容

如同絕大多數的程式語言,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 (布林值)

truefalse 兩個值的布林值,也是 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 一樣可以用 +*-**, 與  % 等運算子,不過要注意不可以拿 BigIntnumber 型別的值交互使用,這會出現 TypeError

Undefined

undefined 是一個型別,它本身也是一個值。假如某個變數還沒被宣告,我們就先使用,在 JavaScript 會出現索引錯誤 ReferenceError (如果是用 letconst 來宣告該變數)。但如果是宣告了,但沒有賦予某個值,這時因為對 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 valResult
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]
🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們