深入探究 null 和 undefined 區(qū)別

大廠技術(shù)??高級前端??Node進(jìn)階
點(diǎn)擊上方?程序員成長指北,關(guān)注公眾號
回復(fù)1,加入高級Node交流群
前言
該文章用了我 兩天 的時間來查各類資料,我盡可能的保證內(nèi)容的 準(zhǔn)確性 。
如果你對任何內(nèi)容有 疑惑 或者 不同的見解 ,歡迎在評論區(qū)友善留言。
如果你是前端新人 ,看到 表現(xiàn)形式 這一章節(jié)就足夠。
剩下的請收藏起來,待到以后想要更深入的了解,再繼續(xù)閱讀。
簡單區(qū)分
總的來說 null 和 undefined 都代表空,主要區(qū)別在于 undefined 表示尚未初始化的變量的值,而 null 表示該變量有意缺少對象指向。
undefined這個變量從根本上就沒有定義 隱藏式 空值 null這個值雖然定義了,但它并未指向任何內(nèi)存中的對象 聲明式 空值
MDN 中給出的定義
null
值?null?是一個字面量,不像?undefined ,它不是全局對象的一個屬性。null?是表示缺少的標(biāo)識,指示變量未指向任何對象。把?null?作為尚未創(chuàng)建的對象,也許更好理解。在 API 中,null?常在返回類型應(yīng)是一個對象,但沒有關(guān)聯(lián)的值的地方使用。
undefined
undefined 是 全局對象 的一個屬性。也就是說,它是全局作用域的一個變量。undefined 的最初值就是原始數(shù)據(jù)類型 undefined 。
一張神奇的圖片
接下來我們看一張比較經(jīng)典的圖片,該圖來自 stackoverflow 的回答,本人沒有找到準(zhǔn)確的出處。
表現(xiàn)形式
在更深入理解 null 和 undefined 的區(qū)別前,我們首先要知道 null 和 undefined 在 JS 中有什么不同的表現(xiàn)形式,用以方便我們更好的理解 null 和 undefined 的區(qū)別。
typeof
typeof?null??//?'object'
typeof?undefined??//?'undefined'
復(fù)制代碼
Object.prototype.toString.call
typeof?null??//?'[object?Null]'
typeof?undefined??//?'[object?Undefined]'
復(fù)制代碼
== 與 ===
null?==?undefined??//?true
null?===?undefined??//?false
!!null?===?!!undefined??//?true
復(fù)制代碼
Object.getPrototypeOf(Object.prototype)
JavaScript 中第一個對象的原型指向 null 。
Object.getPrototypeOf(Object.prototype)??//?null
復(fù)制代碼
+ 運(yùn)算 與 Number()
let?a?=?undefined?+?1??//?NaN
let?b?=?null?+?1??//?1
Number(undefined)??//?NaN
Number(null)??//?0
復(fù)制代碼
JSON
JSON.stringify({a:?undefined})??//?'{}'
JSON.stringify({b:?null})??//?'{b:?null}'
JSON.stringify({a:?undefined,?b:?null})??//?'{b:?null}'
復(fù)制代碼
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
復(fù)制代碼
深入探索
為什么 typeof null 是 object?
typeof null 輸出為 'object' 其實(shí)是一個底層的錯誤,但直到現(xiàn)階段都無法被修復(fù)。
原因是,在 JavaScript 初始版本中,值以 32位 存儲。前 3位 表示數(shù)據(jù)類型的標(biāo)記,其余位則是值。
對于所有的對象,它的前 3位 都以 000 作為類型標(biāo)記位。在 JavaScript 早期版本中, null 被認(rèn)為是一個特殊的值,用來對應(yīng) C 中的 空指針 。但 JavaScript 中沒有 C 中的指針,所以 null 意味著什么都沒有或者 void 并以 全0(32個) 表示。
因此每當(dāng) JavaScript 讀取 null 時,它前端的 3位 將它視為 對象類型 ,這也是為什么 typeof null 返回 'object' 的原因。
為什么 Object.prototype.toString.call(null) 輸出 '[object Null]'
toString() 是 Object 的原型方法,調(diào)用該方法,默認(rèn)返回當(dāng)前對象的 [[Class]]?。這是一個內(nèi)部屬性,其格式為 [object Xxx]?,其中 Xxx 就是對象的類型。
JavaScript 萬物皆對象,為什么 xxx.toString() 不能返回變量類型?
這是因?yàn)?各個類中重寫了 toString 的方法,因此需要調(diào)用 Object 中的 toString 方法,必須使用 toString.call() 的方式調(diào)用。
對于 Object 對象,直接調(diào)用 toString()? 就能返回 '[object Object]' 。而對于其他對象,則需要通過 call / apply 來調(diào)用才能返回正確的類型信息。
為什么 == 和 === 對比會出現(xiàn) true 和 false ?
很多文章說:undefined 的布爾值是 false , null 的布爾值也是 false ,所以它們在比較時都轉(zhuǎn)化為了 false ,所以 undefined == null 。
實(shí)際上并不是這樣的。ECMA 在 11.9.3 章節(jié)中明確告訴我們:
If?x?is?null?and?y?is?undefined, return?true. If?x?is?undefined?and?y?is?null, return?true.
這是 JavaScript 底層的內(nèi)容了,至于更深入的內(nèi)容,如果有興趣可以扒一扒 JavaScript 的源碼。
至于 == 和 === 的區(qū)別,后續(xù)我會在其他文章中詳細(xì)說明。敬請期待!
為什么 null + 1 和 undefined + 1 表現(xiàn)不同?
這涉及到 JavaScript 中的隱式類型轉(zhuǎn)換,在執(zhí)行 加法運(yùn)算 前,隱士類型轉(zhuǎn)換會嘗試將表達(dá)式中的變量轉(zhuǎn)換為 number 類型。如:'1' + 1 會得到結(jié)果 11。
null轉(zhuǎn)化為number時,會轉(zhuǎn)換成0undefined轉(zhuǎn)換為number時,會轉(zhuǎn)換為NaN
至于為什么執(zhí)行如此的轉(zhuǎn)換方式,我猜測是 JavaScript 早期的一個糟糕設(shè)計。
從語言學(xué)的角度來看:null 意味著一個明確的沒有指向的空值,而 undefined 則意味著一個未知的值。
在某種程度上, 0 意味著數(shù)字空值。
這雖然看起來有些牽強(qiáng),但是我在這一階段能所最能想到的可能了。
為什么 JSON.stringify 會將值為 undefined 的內(nèi)容刪除?
其實(shí)這條沒有很好的解釋方式, JSON 會將 undefined 對應(yīng)的 key 刪除,這是 JSON 自身的轉(zhuǎn)換原則。
在 undefined 的情況下,有無該條數(shù)據(jù)是沒有區(qū)別的,因?yàn)樗麄冊诒憩F(xiàn)形式上并無不同:
let?obj1?=?{?a:?undefined?}
let?obj2?=?{}
console.log(obj1.a)??//?undefined
console.log(obj2.a)??//?undefined
復(fù)制代碼
但需要注意的是,你可能在調(diào)用接口時,需要對 JSON 格式的數(shù)據(jù)中的 undefied 進(jìn)行特殊處理。
為什么 let undefiend = 'test' 可以覆蓋掉 JavaScript 自身的 undefined?
JavaScript 對于 undefined 的限制方式為全局創(chuàng)建了一個只讀的 undefined ,但是并沒有徹底禁止局部 undefined 變量的定義。
據(jù)說在 JavaScript 高版本禁止了該操作,但我沒有準(zhǔn)確的依據(jù)。
請在任何時候,都不要進(jìn)行 undefined 變量的覆蓋,就算是你的 JSON 轉(zhuǎn)換將 undefined 轉(zhuǎn)換為 '' 。也不要通過該操作進(jìn)行,這將是及其危險的行為。
總結(jié)
關(guān)于使用 undefined 還是 null
這是一條公說公有理婆說婆有理的爭議內(nèi)容。
本人更傾向于使用 null ,因?yàn)檫@是顯示定義空值的方式。我并不能給出準(zhǔn)確的理由。
但關(guān)于使用 undefined 我有一條建議:
如果你需要使用 undefined 定義空值,請不要采取以下兩種方式:
let a; let a = undefined;
進(jìn)而采取下面這種方式顯式聲明 undefined :
let a = void 0;
結(jié)語
用了兩天時間,終于將 undefined 和 null 的基本區(qū)別搞定了。
如果大家認(rèn)為有任何需要 補(bǔ)充 的,或者有 錯誤 內(nèi)容,請盡快在評論區(qū)留言。
作者:sincenir
Node 社群
我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學(xué)習(xí)感興趣的話(后續(xù)有計劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。
如果你覺得這篇內(nèi)容對你有幫助,我想請你幫我2個小忙:
1. 點(diǎn)個「在看」,讓更多人也能看到這篇文章 2. 訂閱官方博客?www.inode.club?讓我們一起成長 點(diǎn)贊和在看就是最大的支持??
