深入探究:null 和 undefined 究竟有何區別?
前言
該文章用了我 兩天 的時間來查各類資料,我儘可能的保證內容的 準確性 。
如果你對任何內容有 疑惑 或者 不同的見解 ,歡迎在評論區友善留言。
如果你是前端新人 ,看到 表現形式 這一章節就足夠。
剩下的請收藏起來,待到以後想要更深入的瞭解,再繼續閱讀。
簡單區分
總的來說 null
和 undefined
都代表空,主要區別在於 undefined
表示尚未初始化的變量的值,而 null
表示該變量有意缺少對象指向。
-
undefined
-
這個變量從根本上就沒有定義
-
隱藏式 空值
-
null
-
這個值雖然定義了,但它並未指向任何內存中的對象
-
聲明式 空值
MDN 中給出的定義
null
值 null
是一個字面量,不像 undefined
,它不是全局對象的一個屬性。null
是表示缺少的標識,指示變量未指向任何對象。把 null
作爲尚未創建的對象,也許更好理解。在 API 中,null
常在返回類型應是一個對象,但沒有關聯的值的地方使用。
undefined
undefined
是 全局對象 的一個屬性。也就是說,它是全局作用域的一個變量。undefined
的最初值就是原始數據類型 undefined
。
一張神奇的圖片
接下來我們看一張比較經典的圖片,該圖來自 stackoverflow 的回答,本人沒有找到準確的出處。
表現形式
在更深入理解 null
和 undefined
的區別前,我們首先要知道 null
和 undefined
在 JS
中有什麼不同的表現形式,用以方便我們更好的理解 null
和 undefined
的區別。
typeof
typeof null // 'object'
typeof undefined // 'undefined'
複製代碼
Object.prototype.toString.call
typeof null // '[object Null]'
typeof undefined // '[object Undefined]'
複製代碼
== 與 ===
null == undefined // true
null === undefined // false
!!null === !!undefined // true
複製代碼
Object.getPrototypeOf(Object.prototype)
JavaScript
中第一個對象的原型指向 null
。
Object.getPrototypeOf(Object.prototype) // null
複製代碼
+ 運算 與 Number()
let a = undefined + 1 // NaN
let b = null + 1 // 1
Number(undefined) // NaN
Number(null) // 0
複製代碼
JSON
JSON.stringify({a: undefined}) // '{}'
JSON.stringify({b: null}) // '{b: null}'
JSON.stringify({a: undefined, b: null}) // '{b: null}'
複製代碼
let undefiend = 'test'
function test(n) {
let undefined = 'test'
return n === undefined
}
test() // false
test(undefined) // false
test('test') // ture
let undefined = 'test' // Uncaught SyntaxError: Identifier 'undefined' has already been declared
複製代碼
深入探索
爲什麼 typeof null 是 object?
typeof null
輸出爲 'object'
其實是一個底層的錯誤,但直到現階段都無法被修復。
原因是,在 JavaScript
初始版本中,值以 32位
存儲。前 3位
表示數據類型的標記,其餘位則是值。
對於所有的對象,它的前 3位
都以 000
作爲類型標記位。在 JavaScript
早期版本中, null
被認爲是一個特殊的值,用來對應 C
中的 空指針
。但 JavaScript
中沒有 C
中的指針,所以 null
意味着什麼都沒有或者 void
並以 全0(32個)
表示。
因此每當 JavaScript
讀取 null
時,它前端的 3位
將它視爲 對象類型
,這也是爲什麼 typeof null
返回 'object'
的原因。
爲什麼 Object.prototype.toString.call(null) 輸出 '[object Null]'
toString()
是 Object
的原型方法,調用該方法,默認返回當前對象的 [[Class]]
。這是一個內部屬性,其格式爲 [object Xxx]
,其中 Xxx
就是對象的類型。
JavaScript 萬物皆對象,爲什麼 xxx.toString() 不能返回變量類型?
這是因爲 各個類中重寫了 toString
的方法,因此需要調用 Object
中的 toString
方法,必須使用 toString.call()
的方式調用。
對於 Object
對象,直接調用 toString()
就能返回 '[object Object]'
。而對於其他對象,則需要通過 call / apply
來調用才能返回正確的類型信息。
爲什麼 == 和 === 對比會出現 true 和 false ?
很多文章說:undefined
的布爾值是 false
, null
的布爾值也是 false
,所以它們在比較時都轉化爲了 false
,所以 undefined == null
。
實際上並不是這樣的。
ECMA
在 11.9.3
章節中明確告訴我們:
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
這是 JavaScript
底層的內容了,至於更深入的內容,如果有興趣可以扒一扒 JavaScript
的源碼。
至於 ==
和 ===
的區別,後續我會在其他文章中詳細說明。敬請期待!
爲什麼 null + 1
和 undefined + 1
表現不同?
這涉及到 JavaScript
中的隱式類型轉換,在執行 加法運算
前,隱士類型轉換會嘗試將表達式中的變量轉換爲 number
類型。如:'1' + 1
會得到結果 11
。
-
null
轉化爲number
時,會轉換成0
-
undefined
轉換爲number
時,會轉換爲NaN
至於爲什麼執行如此的轉換方式,我猜測是 JavaScript
早期的一個糟糕設計。
從語言學的角度來看:
null
意味着一個明確的沒有指向的空值,而 undefined
則意味着一個未知的值。
在某種程度上, 0
意味着數字空值。
這雖然看起來有些牽強,但是我在這一階段能所最能想到的可能了。
爲什麼 JSON.stringify 會將值爲 undefined 的內容刪除?
其實這條沒有很好的解釋方式, JSON
會將 undefined
對應的 key 刪除,這是 JSON
自身的轉換原則。
在 undefined
的情況下,有無該條數據是沒有區別的,因爲他們在表現形式上並無不同:
let obj1 = { a: undefined }
let obj2 = {}
console.log(obj1.a) // undefined
console.log(obj2.a) // undefined
複製代碼
但需要注意的是,你可能在調用接口時,需要對 JSON
格式的數據中的 undefied
進行特殊處理。
爲什麼 let undefiend = 'test' 可以覆蓋掉 JavaScript 自身的 undefined?
JavaScript
對於 undefined
的限制方式爲全局創建了一個只讀的 undefined
,但是並沒有徹底禁止局部 undefined
變量的定義。
據說在 JavaScript
高版本禁止了該操作,但我沒有準確的依據。
請在任何時候,都不要進行 undefined
變量的覆蓋,就算是你的 JSON
轉換將 undefined
轉換爲 ''
。也不要通過該操作進行,這將是及其危險的行爲。
總結
關於使用 undefined 還是 null
這是一條公說公有理婆說婆有理的爭議內容。
本人更傾向於使用 null
,因爲這是顯示定義空值的方式。我並不能給出準確的理由。
但關於使用 undefined
我有一條建議:
如果你需要使用 undefined
定義空值,請不要採取以下兩種方式:
-
let a;
-
let a = undefined;
進而採取下面這種方式顯式聲明 undefined
:
- let a = void 0;
結語
用了兩天時間,終於將 undefined
和 null
的基本區別搞定了。
如果大家認爲有任何需要 補充 的,或者有 錯誤 內容,請儘快在評論區留言。
關於本文
作者:sincenir
https://juejin.cn/post/7051144396615450655
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/CoIWXZ1mE8EG0ytVEzaOYQ