iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 6
3
Modern Web

跟著 YDKJS 作者 Kyle Simpson 打造全新 JavaScript Mindset系列 第 6

[day05] YDKJS (Type) : 初學者第一坑 - typeof 運算子, 詳解 undefined

  • 分享至 

  • xImage
  •  

typeof

typeof 是一個 運算子(operator)Return a String

當我們用 typeof operator, 我們真正問的問題是
「 現在在變數(v)裡面的『值』,它的型別是什麼?」
而不是要問的變數 v的型別是什麼。
(變數沒有型別,值才有)

有些時候,我們使用 Object.prototype.toString.call 加上正規運算式和陣列以區分型別最後的回傳,而非 typeof operator。
因為 typeof operator 的結果和型別並 沒有一一對應

typeof undefined     === "undefined"; // true , 回傳是字串不是 undefined
typeof true          === "boolean";   // true
typeof 42            === "number";    // true
typeof "42"          === "string";    // true
typeof { life: 42 }  === "object";    // true

// 在 ES6 中被加入的!
typeof Symbol()      === "symbol";    // true

and

typeof null === "object"; // true, oops!
typeof function a(){ /* .. */ } === "function"; // true , hmmmm?
typeof [1,2,3] === "object"; // true, hmmmm?

來讀 Specification:

理論上回傳值都要是左邊 Type of val 的值(top level type),但基於一些歷史原因,有些著名的 bug 被留下來。

知名 bug 如:

  1. Null 回傳 Object 是一個 Bug

    • 你如果拿到 typeof 回傳是一個 object, 他有可能是 null
  2. Function 回傳 不是 Object

    • 你如果拿到 typeof 回傳是一個 "function", 他是 "function"
    • 但你永遠拿不到 typeof 回傳是一個 "Array",因為會回傳 "Object"
  3. 對 Host object 使用 typeof

    • Host object 前提是沒有實作 Call,因為有實作就視為 function
    • 如果是 typeof new val(建構式) ,回傳 Object
    • 如果是 typeof 包裝物件(wrapper objects) ,回傳 包裝物件(wrapper objects) 之後的型別。

    Reference code : MDN

    typeof new Boolean(true) === 'object'; // 這樣會令人混淆。不要這樣用!
    typeof new Number(1) === 'object'; // 這樣會令人混淆。不要這樣用!
    typeof new String("abc") === 'object';  // 這樣會令人混淆。不要這樣用!
    
    typeof Boolean(true) === 'boolean'; // 但是不要使用這種方式!
    typeof Number(1) === 'number'; // 但是不要使用這種方式!
    typeof String("abc") === 'string'; // 但是不要使用這種方式!
    
    
    // 對於 Array
    typeof [1, 2, 4] === 'object'; // 請使用 Array.isArray 或者 Object.prototype.toString.call 以區分正規運算式和陣列
    
    
  4. 對於 Host object 可能是 undefined

    • browsers(Chrome 版本 76.0.3809.132 (正式版本) (64 位元) 之下 輸入 document.all

    Host object 回傳應該是取決於執行當下的環境(provided by the JS environment),但瀏覽器回傳 'undefined' 是一個 刻意的違規(willful violation)。

    (typeof bug 夠多了,web standards還故意來鬧 = = )

  5. 原本 typeof 應該必定回傳 string ,但 ES6 使用 let / const 之類的語法有可能產生 Error 中斷程式。

後面文章會提到 let / const 的 TDZ error 問題

Reference : mdn typeof - Error


這邊花一點篇幅再補充一下 undefined

undefined

  • Undefined 類型 有,且只有一個值 (aka 存在且唯一),稱為 undefined
  • 任何沒有被賦值的變數都有 undefined 值。

在我們思考 typeof 的值時,其實在意的不是 變數 v 的 type(文章開始有提過)。
所以 line 2 回傳的型別,可以視為是一種 沒有 assign 任何值(value) 的 預設(default)
稱作 undefined (此處 undefined -> value)。

因為 剛好 這個預設值 (value) 和 undefined type 的值一樣,
所以我們判斷這個型別也是 undefined ( 此處 undefined -> type )。

還有一個很常見的狀況是,這個 變數 v 可能會 assign 其他值,此時 變數(v) 的型別就是 「值」 的型別。

但有時候 變數(v) 會被設定回 undefined 當作把值清空 ,
You set it to undefined, you undefine it.。

上述這種情況很常見,因為你沒有刪除 (delete) 變數,
也沒有移除 (remove) 變數, 變數(v) 也不會莫名其妙消失。

所以讓 變數 回歸 一開始 「沒有 assign 任何值的預設 」的狀態,
這個狀態的「值」就是 undefined (value)。

因為值是 undefined,所以我們判斷型別也是 undefined。

這個是 Kyle Simpson 用 JS 的慣例,把變數清空用 undefined 。 有些人可能是用 null。

undefined 沒有任何方法、沒有任何相應的“包裝物件(wrapper objects)”,所以可以說他是「最原始的 (the most primitive) 」之一 ( 另一個是 null )。

alert(undefined.test); // error

null表示"沒有物件",即該處不應該有值。

  1. 作為函式的參數,表示該函式的參數不是物件。
  2. 作為物件原型鏈的終點。

Object.getPrototypeOf(Object.prototype)

undefined表示"缺少值",就是此處應該有一個值,但是還沒有定義。典型用法是:

  1. 變數被聲明了,但沒有賦值時,就等於 undefined。
  2. 呼叫函式時,應該提供的參數沒有提供,該參數等於 undefined。
  3. 物件沒有 "沒有賦值"的屬性,該屬性的值為 undefined。
  4. 函式沒有回傳值時,預設回傳 undefined。

作者傾向 NaN / undefined 的結果顯示的語意 (後文會提到 NaN)

undefined 代表的是「(此變數) 還沒有給值,所以不知道是什麼」
null 代表的是「(此變數可能曾經有值,可能沒有值) 現在沒有值」
我想這點在透過 Number() 強製為兩者轉型的時候多少可以看出點什麼:

Number( null ); // 0

Number( undefined ); // NaN


上一篇
[day04] YDKJS (Type) : Value 才有型別,變數沒有
下一篇
[day06] YDKJS (Type) : 特殊值:undefined / undeclared / TDZ ? , NaN , 負數 0
系列文
跟著 YDKJS 作者 Kyle Simpson 打造全新 JavaScript Mindset31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言