Javascript Pro(一)JS的資料型態、typeof原理、Symbol與bigint

Andy Cheng
Andy的趣味程式練功坊
9 min readAug 13, 2021

前言

嗨大家,因為之前的Vue系列點閱率還不錯(雖然已經是兩年前),但最近為了面試回來看JS核心進階的部分,因此寫文章來紀錄學到的JS,其中會盡量以故事及好閱讀的方式介紹,參雜一些自己製作的低成本圖文,再請大家好好期待囉。

誰適合看這一系列的文章

希望你是具有JS基本功底,會用基本的JS語法,如變數、函數、DOM操作,還有重要的是ES6基礎知識。因此這系列文章不會再討論基本的for、while等基本知識,而是更專注於JS中比較難理解的底層部分,因為這系列文章是一邊寫一邊學,因此不確定會有幾個章節,那麼如果你準備好,就跟我一起踏上這次的旅程吧。

JS的基本資料型態有哪些?你對這些又多深入了解呢

如果想探討JS在底層是如何運行,那麼資料型態肯定是我們需要先熟悉的部分,因為不同的資料型態在記憶體中儲存的方式也不同,所以我們先從最基本的資料型態來介紹起。

此時讀者表示:你第一篇就說要深入探討JS,那怎麼教這麼簡單的東西呢?欸別急別急,當然不是要討論資料類型有哪些而已,還會更深入討論一些你可能不知道的特性。

在JS當中,總共有七大原始(Primitive)資料型態及引用(object)資料型態:

七大基本資料型態

  • number
  • string
  • boolean
  • null
  • undefined
  • symbol
  • bigint

基本資料型態又稱值類型原始數據類型,其實可以想成是一個無法再進行分解的資料,首先是number,也就是0,1,2,…等數字,需要注意的是他的值還有NaN,Infinity這兩種,然後string也就是用””包起來的字串,boolean則是有true, false兩種值,比較會搞混及面試常出現的是null及undefined ,接著我們較少用的能代表唯一值的symbol和大數據類型bigint。

引用資料類型

  • object
  • function

引用資料型態主要代表人物就是object和function,其中上圖有顯示這兩種資料型態包含了什麼東西,這些東西其實也是JS中比較困難的部分,各位應該不太陌生,他們的進階用法我們之後會詳細說明。

這些資料型態我們要怎麼樣才能真正掌握呢?就由下面這些題目來幫助我們吧!

1. 說說你最常用的檢測資料型態的方式

說到檢測資料型態,我們最先想到的一定是typeof,instanceof,其他還有Object.prototype.toString,因為檢測資料型態的資訊量過大,我們本篇先僅討論typeof,之後再來深入討論這些。

typeof是JS的一種用來檢測資料型態的方法,當然他也有很多缺點,首先我們先看看他的用法,直接開啟瀏覽器的console,輸入下面的程式,可以看到typeof會返回一個字串給我們。

typeof 10 => "number"
typeof NaN => "number"
typeof "" => "string"
typeof undefined => "undefined"
typeof Symbol() => "symbol"
typeof {} => "object"
typeof function(){} => "function"

乍看之下蠻完美的,都有檢測出我們想要的值,但當有一天,你想要檢測一個類型是否為null時,他出問題了。

typeof null => "undefined"

接著你也想檢測一個物件是正則物件還是陣列物件,你卻發現:

typeof {} => "object"
typeof [] => "object"

我們得出了一個結論:typeof 無法細分物件

這時候你說這我也知道,我早就背起來了,那麼再問一個問題,為什麼呢?

typeof無法細分物件的原因

我們知道所有的資料型態在電腦中儲存時,都是按造二進制去儲存的,而像null 的儲存內容就是:0x000000,此外,只要資料型態是物件的,都是以000開頭,說這些就是因為,typeof進行檢測時是按造電腦儲存的二進制值進行檢測。這麼一來就能解釋為什麼typeof {}, typeof []都是輸出object了。

typeof的使用場景

  • 識別基本資料型態,如:number、string、等等,但不適合用來檢測更需要細分的物件或函數。

2. NaN 及 Infinity

Infinity是描述一個無限大的數,本身是一個特定的值就叫做Infinity,我們可以在console中輸入:

Infinity === Infinity 

console會告訴我們兩者是一樣的,而Infinity 也有正負之分,負無窮大-Infinity 不會相等Infinity

接著是NaN,NaN的意思是「不是一個數字」,用他來進行比較時,他跟誰都不相等,就好像你罵一個人說:「你不是一個人」,這個意思就是說,他可以是任何東西,就絕對不是人,因此也可以這樣來記NaN,因此,它當然跟自己也不相同。

NaN === NaN //false

檢測NaN的方法

如果我想檢測你傳的是不是一個有效數字,我們能不能用下列這個式子來檢測呢?

if(n === NaN){
console.log(n+"不是有效數字");
}

答案是不行的,因為NaN跟誰都不相等,就算n是NaN,結果還是false,因此你得用一個函數isNaN 來檢測,如果為true 代表他不是有效數字,如果為false 則代表他是有效數字,我們改寫我們的判斷式:

if(!isNaN(n)){
console.log(n+"是有效數字");
}

補充:另一個檢測NaN方法 — Object.is(NaN,NaN)

3. Symbol

Symbol是我們還是JS新手時,非常少用的一種資料型態,它的功用是描述一個唯一值,我們看到Symbol時可能會想到,疑它的首字母是大寫的,那麼他是不是算是一個class,能否被new呢?答案是否定的,Symbol並無法被new。

new Symbol() // Uncaught TypeError: Symbol is not a constructor

它的使用方式就是直接使用Symbol() 即可創造一個唯一值,那怎麼確定它是唯一值呢?

console.log(Symbol() === Symbol()) // false

每次執行一次Symbol()方法,都會創造一個獨一無二的值,Symbol支持傳入一個字串來標記Symbol,讓我們開發時能識別,就算使用兩個一樣的標記字串來執行Symbol方法也不會相等。

 console.log(Symbol('abc') === Symbol('abc')) // false

但使用let先將結果存起來再跟自己比較就會是true

let symb = Symbol('abc');
console.log(symb === symb); // true

Symbol的作用

Symbol的作用就是給物件設置一個唯一的屬性,或在vuex/redux做dispatch時,統一管理dispatch派發的行為標記,標記的值可以是唯一值,在後面會再說明。此外,Symbol有很多更厲害的功能,我們可以使用dir來看一下Symbol的方法:

裡面有許多好用的方法,例如:instanceof 的檢測原理:hasInstance,把物件轉換成字串或數字會用到的 toPrimitive,讓集合具備可迭代性的 iterator…等方法。Symbol本身提供的這些方法可能比創建唯一值更常被使用,這些東西在JS核心底層的原理,都會被使用到,這才是Symbol的重點,不過本篇文章中不會深入探討Symbol,僅先做介紹,之後有用到時再講解。

4. bigint

在JS中我們已經有number這個類型,但為什麼還會出現bigint呢?原因是number的最大數,是一個定值,我們可以用Number.MAX_SAFE_INTEGER來查看:

這是Number的最大安全數,當我們的數字超過它時再進行運算就會發現它算起來跟你想得開始不一樣:

最後一個數字應該要是5

那麼在我們的資料庫中可能存了一個非常長的ID如:9007199254740991999,超過了最大安全數字,如果後端給我們返回的值並沒有用字串而是用數字返回,這樣可能我們得到的ID會錯誤,你可以說後端可以給我們返回字串不就沒事了,但有些後端工程師可能對瀏覽器JS沒有概念,此時就需要bigint來處理。

bigint(大數)是ES6出現的新類型,它能幫助我們處理非常大的數字,使用方法十分簡單,只要在數字後面加上n 就能創建一個大數。

typeof 9007199254740991999 =>"bigint"

使用大數後我們相加相減都沒有問題了:

這次介紹了一些JS中比較少使用的資料型態,下一篇我們會探討這些資料型態在記憶體中的儲存方式的不同,再請期待囉。

我是Andy,謝謝你看完這篇文章,如果文章有幫助到你的話,希望不吝於幫我拍手 🙌🙌

--

--

Andy Cheng
Andy的趣味程式練功坊

若能將學到的知識轉化為易懂的文章,才能算是真正學會。這是我創建這個帳號的初衷。