JavaScript共有八種資料型別,分別是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。
Symbol 和 BigInt
其中Symbol 和 BigInt 是 ES6+(ECMAScript 2015+)中新增的資料型別:
-
Symbol 可以理解為一個獨特的識別符號。想象一下,你有一把獨一無二的鑰匙,這把鑰匙就是 Symbol。它的主要用途是避免在使用物件屬性時發生意外的名字衝突。比如,如果你和別人合作開發一個大型專案,你們都想給一個物件新增一個叫"id"的屬性,使用 Symbol 可以確保你們的"id"不會互相覆蓋。 -
BigInt 是專門用來處理特別大的整數的。普通的 Number 型別在JavaScript中有一個最大安全整數(9007199254740991),超過這個數字可能會出現計算錯誤。而 BigInt 可以安全地表示和計算任意大的整數,就像是給了數字一個無限的跑道。比如,當你需要精確計算天文數字或者處理非常大的金融資料時,BigInt 就非常有用。
這兩種資料型別的加入,使得 JavaScript 能夠更好地處理獨特標識和超大整數,增強了語言的功能性和適用範圍。
簡單型別和複雜型別
JavaScript 的資料型別可以分為兩大類:簡單型別和複雜型別。
-
簡單型別(也叫原始型別):
-
這些型別就像是一個個小盒子,每個盒子裡直接裝著一個值。 -
包括:Undefined、Null、Boolean、Number、String、Symbol 和 BigInt。 -
它們儲存在計算機的"棧"記憶體中,就像一摞盤子,取用方便快捷。 -
複雜型別(也叫引用型別):
-
這些型別更像是大箱子,裡面可以裝很多東西。 -
主要是 Object 型別,包括普通物件、陣列和函式。 -
它們儲存在"堆"記憶體中,就像一個大倉庫,可以存放更多、更復雜的資料。
簡單來說,簡單型別就是單純的資料,複雜型別則可以包含更多資訊和功能。
兩種型別的區別在於儲存位置的不同:
-
棧記憶體:原始資料型別就像是小紙條,上面寫著簡單的資訊(如數字或文字)。這些小紙條直接放在一個叫"棧"的抽屜裡。這個抽屜很小,但是拿東西特別快,所以經常用到的小紙條就放在這裡。 -
堆記憶體:引用資料型別則像是大箱子,裡面可能裝著很多東西(如各種衣物)。這些大箱子放在一個叫"堆"的大倉庫裡。因為箱子太大了,不能直接放在小抽屜裡,所以我們在小抽屜裡放了一張寫有箱子位置的便利貼。當我們需要箱子裡的東西時,先在抽屜裡找到便利貼,然後按照便利貼上的位置資訊去倉庫裡找到對應的箱子。
資料型別檢測
-
typeof: 7種基礎資料型別中除了 null 返回的是 object,其他都能準確返回(包括 Symbol 返回 symbol,BigInt 返回 bigint),複雜資料型別中 Function 型別的資料返回 function,其他都返回 object;
console.log(typeof 42); // 輸出: "number"
console.log(typeof "Hello"); // 輸出: "string"
console.log(typeof true); // 輸出: "boolean"
console.log(typeof Symbol()); // 輸出: "symbol"
console.log(typeof 42n); // 輸出: "bigint"
console.log(typeof null); // 輸出: "object"
console.log(typeof {}); // 輸出: "object"
console.log(typeof []); // 輸出: "object"
console.log(typeof function(){}); // 輸出: "function"
-
instanceof: 複雜資料型別如Array等都準確返回相應的boolean值,對於基本資料型別則是返回 false (只有是透過new運算子來進行初始化,然後透過instanceof來判斷是否是某個類的例項,才會返回true,比如"var k = new Number(11); console.log(k instanceof Number)",其返回true);
console.log([] instanceof Array); // 輸出: true
console.log({} instanceof Object); // 輸出: true
console.log(new Date() instanceof Date); // 輸出: true
console.log(42 instanceof Number); // 輸出: false
console.log(new Number(42) instanceof Number); // 輸出: true
-
使用constructor檢測:上面的instanceof對於直接宣告如:"var a = 1;" 不能進行判斷,我們可以透過使用constructor來實現判斷,如 "a.constructor==Number" (其返回true,不過對於"1.constructor==Number"這類直接用數值來訪問 constructor 的情況是會報錯的),但對於null則仍然無法判斷 ,而且會報錯,比如"var k = null; console.log(k.constructor==Object)";
console.log((42).constructor === Number); // 輸出: true
console.log("Hello".constructor === String); // 輸出: true
console.log([].constructor === Array); // 輸出: true
console.log(({}).constructor === Object); // 輸出: true
// console.log(null.constructor === Object); // 這行會報錯
-
使用Object.prototype.toString.call使用:這個方法可以獲取所有的型別(包括null型),不過其返回的是類似"object Array"的形式的字串。
console.log(Object.prototype.toString.call(42)); // 輸出: "[object Number]"
console.log(Object.prototype.toString.call("Hello")); // 輸出: "[object String]"
console.log(Object.prototype.toString.call(true)); // 輸出: "[object Boolean]"
console.log(Object.prototype.toString.call(null)); // 輸出: "[object Null]"
console.log(Object.prototype.toString.call(undefined)); // 輸出: "[object Undefined]"
console.log(Object.prototype.toString.call([])); // 輸出: "[object Array]"
console.log(Object.prototype.toString.call({})); // 輸出: "[object Object]"
console.log(Object.prototype.toString.call(function(){})); // 輸出: "[object Function]"
注意事項
-
null
的型別檢測: -
使用 typeof null
會返回"object"
,這是 JavaScript 的一個歷史遺留 bug。 -
要準確檢測 null
,可以使用嚴格相等:value === null
-
原始值包裝物件:
-
JavaScript 會自動為原始值建立包裝物件,這就是為什麼我們可以在原始值上呼叫方法。 -
例如: "hello".toUpperCase()
實際上 JavaScript 會臨時建立一個 String 物件。 -
Symbol 的特殊性:
-
Symbol 值是唯一的,即使描述相同,兩個 Symbol 也不相等。 -
例如: Symbol('foo') !== Symbol('foo')
-
BigInt 的使用:
-
BigInt 數字後面要加 n
,例如:const bigInt = 1234567890123456789012345678901234567890n;
-
BigInt 不能與普通數字進行混合運算。 -
型別轉換:
-
JavaScript 中的型別轉換可能會導致意外結果,例如:
console.log([] + []); // 輸出空字串 ""
console.log([] + {}); // 輸出 "[object Object]"
console.log({} + []); // 輸出 0 (在某些環境下)