跟著 YDKJS 作者 Kyle Simpson 打造全新 JavaScript Mindset : 特殊值(undefined , NaN , Null)
什麼是 undefined ?
Javascript 試圖假裝「宣告不是很重要」,你可以有其他權宜之計(work around it)
Kyle Simpson 認為,這個部分不應該這樣做,應該 returned a string undeclared
.
undeclared 表示它還沒有在 作用域(scope) 內建立
而 undefined 表示我們宣告一個變數,不過在這時候還 沒有賦值(no value).
很可惜,我們沒有 undeclared
,所以大家對這個值常常混淆。
常見的 var x
「預設值是 undefined」 。
如果可以,
javascript 一定要宣告,那這樣的話沒有宣告的變數就是 Undeclared
,代表「變數沒有被建立
」。
ES6之後,一個狀態 uninitialized
,「存在」有一個變數但是「還沒有被初始化
」,這時候大家都不能碰,否則就是TDZ (temporal dead zone) Error。
這是我自己理解畫的圖:
因為 Undeclared 不存在,如果在非嚴格模式底下,JS 會自作聰明的幫你宣告。
順帶一提,「宣告」這件事,有關 hoisting ,未來文章有機會介紹。
真正來說,undefined
就是個普通的原始值,跟 2
或者 "hello"
是一樣的。
只不過使用時要謹慎。
undefined
、null
是只有一個且唯一的「值」。
然而,null
也是個騙子。
由於 JavaScript 中的一個 bug,它會被識別成一個物件。
console.log(typeof(null)); // “object” (騙人啊!)
你可能在玩 JS踩地雷 或是 JS面試大補帖 之類的小遊戲(?),
對 null 的坑可能就有所了解。
早期我使用 undefined
當作 reset 一個變數的方法,
目前我比較多使用 null,
可以避免和 原始值
的語義混淆。
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
,只是其「值」是一個特殊狀態
。
NaN 有參與的任何 numeric 運算(比如字串減法),結果都是 NaN。
這個問題,思考的核心是 Invalid number 的運算是沒意義
的(Invalid),
自然就回傳 Invalid number,也就是這邊的 Invalid 代表 沒意義
。
如果解釋成 Not a Number ,很難理解關聯。
- Invalid number 與任何數字運算,整個運算式也仍然表示 Invalid ( Invalid 狀態 a.k.a. 警戒值)
- 常見於 減法運算,
subtraction operator(-)
限定數字運算,所以會強制轉型成numbers
,不像加法有運算子多載 (可以做字串運算)
NaN === NaN
// false
順帶一提,整個 js 只有這組特殊值 自己不等於自己
IEEE_754 規範 spec 明確指出 :
NaN 與任何浮點數(包括自身)的比較結果都為假,即 (NaN ≠ x) = false.
isNaN
isNaN(some var) 。var 在比對以前,也會強制轉型成數字,所以字串被轉型成 NaN
很顯然強制轉型是一個爛想法,所以 ES6 以後可以透過 Number.isNaN
做不轉型的比對。
關於 Kyle Simpson 思想
一般來說,IEEE 754 回傳拿到 NaN 是在純數字運算
,
但是如果發生一種狀況:數字運算,結果回傳不是數字
,所以才會設計回傳 Invalid number
a.k.a. NaN
。
很顯然這種狀況對不知道 數字運算,結果回傳不是數字
要怎麼思考的人,造成很大困難。
有人就抱怨:
不應該存在
或 不應該使用NaN 當作回傳 !
延伸這個問題:那麼你要設計什麼回傳?
如果今天沒有 NaN,那今天遇到不是數字(或是 Invalid number)
的回傳,可以回傳什麼?
- 回傳
undefined / null / false
:
如果數字運算,忽然變成回傳其他型別
,你一定會後悔。
你可能想,「ok, 那我設計回傳數字!」
- 回傳
-1
:
基於歷史原因,比如 Array 中的遍歷,失敗時會回傳 -1。
但回傳 -1 是因為 C語言 時期 40 多年以前還沒有 IEEE 的標準
,才逼不得已。
所以 你要放棄IEEE 的標準
,造成更多問題嗎? (為何實作一半) - 回傳
0
:
你會很容易遇到強制轉型問題,
而且語意來說,0 是有意義
不是沒有回傳
。
所以,如果今天你設計系統,改寫使用自定義
的非 NaN
的回傳時,請仔細測試它,否則你會產生其他 bug。