iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 7
1
Modern Web

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

[day06] YDKJS (Type) : 特殊值:undefined / undeclared / TDZ ? , NaN , 負數 0

  • 分享至 

  • xImage
  •  

這也是一個歷史原因的 Bug (historical wart)。

Javascript 試圖假裝「宣告不是很重要」,你可以有其他權宜之計(work around it)

(JavaScript trying to pretend as if the absence of a declaration isn't that big a deal)

Kyle Simpson 認為,這個部分不應該這樣做,應該 returned a string undeclared.

  • undeclared 表示它還沒有在 作用域(scope) 內建立

it's never been created in any scope that we have access to

  • undefined 表示我們宣告一個變數,不過在這時候還 沒有賦值(no value).

  • uninitialized (尚未初始化) aka TDZ (temporal dead zone)

TDZ

因為沒有 Undeclared ,產生一個在 ES6 之後最常見的 Error 。

uninitialized 想法是,有一個 block 的作用域,那塊作用域不能被宣告,甚至「不能被 undefined」,任何操作都是禁止的。

如果你嘗試操作那一塊 uninitialized 狀態的區域,那你會得到錯誤,那個錯誤就是 TDZ 錯誤。

個人小總結

這邊 Kyle Simpson 把常見的 var x 「預設值是 undefined」 , 開始回推變數週期。

如果可以,javascript 一定要宣告,那這樣的話沒有宣告的變數就是 Undeclared,代表「變數沒有被建立」。

ES6之後,一個狀態 uninitialized ,「存在」有一個變數但是「還沒有被初始化」,這時候大家都不能碰,否則就是TDZ Error。

這是我自己理解畫的圖:

這邊還沒有實際提到 TDZ , 因為是 scope 才會比較詳細提到。
還要多補充一個東西,因為 Undeclared 不存在,如果在非嚴格模式底下,JS 會自作聰明的幫你宣告,這就是常常聽到 hoisting 的感覺,不過 hoisting 也是後面文章的內容。


NaN - isNaN

來自 IEEE 754 規範。 IEEE 754 定義 (NaN ≠ x) = false.
不要理解成 Not a Number 的縮寫,理解成 Invalid number

要理解 NaN ,應該想成 NaN 是一個 警戒值(sentinel values),表示 Invalid number 數字無效的狀態。

*註:警戒值(sentinel values): 比如迴圈的終止條件寫 -1,這時候不是真的有一個值會是 -1,只是一個用來判斷終止條件的「狀態」。

為甚麼會說 Invalid number 比起 Not a Number 是更好的解釋?

  1. typeof NaN === "number" : 從字面上解釋,與 Not a Number 語意不符,
    Invalid number 可以從字面上解釋解釋,因為 Invalid number 還是 number。
    • 也可以從定義解釋 : (IEEE 754 spec which is a numeric representation specification.)
      IEEE 754 是專門 規範 numeric 的文件,當然「型別」還是 number,只是其「值」是一個特殊狀態。
  2. NaN 有參與的任何 numeric 運算(比如字串減法),結果都是 NaN。
    可以思考成 Invalid number 的運算是沒意義的(Invalid),自然就回傳 Invalid number。
    • Invalid number 與任何數字運算,整個運算式也仍然表示 Invalid ( Invalid 狀態 a.k.a. 警戒值)
    • subtraction operator(-) needs numbers,所以會強制轉型成 numbers,不像加法有運算子多載。
  3. NaN === NaN // false 。順帶一提,整個 js 只有這組特殊值 自己不等於自己

IEEE_754 規範 spec 明確指出 : NaN 與任何浮點數(包括自身)的比較結果都為假,即 (NaN ≠ x) = false.

  • line 1 : 用8進位表示數字

    補充: 其他表示法

    let bi = 0b11111111; // binary form of 255
    let oct = 0o377; // octal form of 255
    let hex = 0xFF; // Hexadecimal form of 255
    let samehex = 0xff; // (the same, case doesn't matter)
    
    alert( a == b ); // true, the same number 255 at both sides
    alert( a === b ); // true, the same number 255 at both sides
    
    
  • line 3 : 如果我沒有貓,我沒有任何數學形式可以表示。
    有人會用 0 ,但數學上 0 絕對是有很重要意義的單位,不應該用來表示 「沒有」的佔位符號 (place holder)。數學上不合理,程式中也不合理。

    所以 IEEE 的標準裡面才會實現特殊但有意義的值(special bit pattern)來清楚呈現。

    Reference: wiki

  • line 6 : IEEE754 定義 (NaN ≠ x) = false.

  • line 10:

    isNaN(var) 。var 在比對以前,也會強制轉型成數字,所以字串被轉型成 NaN

  • line 12,13:

    很顯然強制轉型是一個爛想法(參考 line 10 強制轉型),所以 ES6 以後可以透過 Number.isNaN 做不轉型的比對。


一般來說(IEEE 754),回傳拿到 NaN 是在純數字運算但是回傳不是數字,所以回傳 Invalid number a.k.a. NaN。
有人就抱怨不應該存在 或 不應該使用 NaN 當作回傳,那麼你要設計什麼回傳?

如果今天沒有 NaN,那今天遇到不是數字(或是 Invalid number)的回傳,可以回傳什麼?

  • undefined / null / false : 如果數字運算,忽然變成回傳其他型別,你一定會後悔
  • -1 : 基於歷史原因,比如 Array 中的遍歷,失敗時會回傳 -1。
    但回傳 -1 是因為 C語言 時期 40 多年以前還沒有 IEEE 的標準,才逼不得已。
    所以 JS 是 40 多年的語言嗎?
  • 0 : 你會遇到強制轉型問題,而且語意來說,0 是有意義不是 沒有回傳

所以,如果今天你設計系統,考慮使用非 NaN 的回傳時,請仔細測試它,否則你會產生其他 bug。


negative-zero

有負號的 0
IEEE 754 有定義

  • line 4: 負號不見。
  • line 5: 嚴格相等 還騙人,=== 並沒有用。
  • line 6,7: 看起來像一個 bug,和 嚴格相等 一樣騙人。
  • line 9,10 : ES6以前都沒有方法可以知道 -0 到底存不存在。

看起來很多 bug 的 negative-zero,Kyle Simpson 實際運用於判斷地圖上的移動,在位移量為零時,可以知道是不是同方向。

同樣也可以用於遊戲,因為數學上用 + , - 當作方向判斷是很常見的。

股票上也可以用類似的方法去做設計。

最大的好處是不用存兩個變數:方向,和數值
壞處是,不熟悉的人的可能會有錯誤的操作。

練習題: 實作 Object.is

可以拿 gist 的 console 當作 test case.

gist 有解答 要練習直接複製 console 當 tests


ans:
找 negative-zero :

用 infinity / value => infinity or -infinity


上一篇
[day05] YDKJS (Type) : 初學者第一坑 - typeof 運算子, 詳解 undefined
下一篇
[day07] YDKJS (Type/Coercion) : 來讀 Abstract Operations Spec. : ToPrimitive()
系列文
跟著 YDKJS 作者 Kyle Simpson 打造全新 JavaScript Mindset31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言