深入學習下 null 和 undefined 區(qū)別

作者:sincenir
https://juejin.cn/post/7051144396615450655?
前言
該文章用了我?兩天?的時間來查各類資料,我盡可能的保證內(nèi)容的?準確性?。
如果你對任何內(nèi)容有?疑惑?或者?不同的見解?,歡迎在評論區(qū)友善留言。
如果你是前端新人 ,看到?表現(xiàn)形式?這一章節(jié)就足夠。
剩下的請收藏起來,待到以后想要更深入的了解,再繼續(xù)閱讀。
簡單區(qū)分
總的來說?null?和?undefined?都代表空,主要區(qū)別在于?undefined?表示尚未初始化的變量的值,而?null?表示該變量有意缺少對象指向。
undefined這個變量從根本上就沒有定義 隱藏式 空值 null這個值雖然定義了,但它并未指向任何內(nèi)存中的對象 聲明式 空值
MDN 中給出的定義
null
值?null?是一個字面量,不像?undefined?,它不是全局對象的一個屬性。null?是表示缺少的標識,指示變量未指向任何對象。把?null?作為尚未創(chuàng)建的對象,也許更好理解。在 API 中,null?常在返回類型應是一個對象,但沒有關聯(lián)的值的地方使用。
undefined
undefined?是?全局對象?的一個屬性。也就是說,它是全局作用域的一個變量。undefined?的最初值就是原始數(shù)據(jù)類型?undefined?。
一張神奇的圖片
接下來我們看一張比較經(jīng)典的圖片,該圖來自 stackoverflow 的回答,本人沒有找到準確的出處。
表現(xiàn)形式
在更深入理解?null?和?undefined?的區(qū)別前,我們首先要知道?null?和?undefined?在?JS?中有什么不同的表現(xiàn)形式,用以方便我們更好的理解?null?和?undefined?的區(qū)別。
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'?其實是一個底層的錯誤,但直到現(xiàn)階段都無法被修復。
原因是,在?JavaScript?初始版本中,值以?32位?存儲。前?3位?表示數(shù)據(jù)類型的標記,其余位則是值。
對于所有的對象,它的前?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?的原型方法,調(diào)用該方法,默認返回當前對象的?[[Class]]?。這是一個內(nèi)部屬性,其格式為?[object Xxx]?,其中?Xxx?就是對象的類型。
JavaScript 萬物皆對象,為什么 xxx.toString() 不能返回變量類型?
這是因為 各個類中重寫了?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?。
實際上并不是這樣的。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ù)我會在其他文章中詳細說明。敬請期待!
為什么?null + 1?和?undefined + 1?表現(xiàn)不同?
這涉及到?JavaScript?中的隱式類型轉(zhuǎn)換,在執(zhí)行?加法運算?前,隱士類型轉(zhuǎn)換會嘗試將表達式中的變量轉(zhuǎn)換為?number類型。如:'1' + 1?會得到結(jié)果?11。
null?轉(zhuǎn)化為?number?時,會轉(zhuǎn)換成?0undefined?轉(zhuǎn)換為?number?時,會轉(zhuǎn)換為?NaN
至于為什么執(zhí)行如此的轉(zhuǎn)換方式,我猜測是?JavaScript?早期的一個糟糕設計。
從語言學的角度來看:null?意味著一個明確的沒有指向的空值,而?undefined?則意味著一個未知的值。
在某種程度上,?0?意味著數(shù)字空值。
這雖然看起來有些牽強,但是我在這一階段能所最能想到的可能了。
為什么 JSON.stringify 會將值為 undefined 的內(nèi)容刪除?
其實這條沒有很好的解釋方式,?JSON?會將?undefined?對應的 key 刪除,這是?JSON?自身的轉(zhuǎn)換原則。
在?undefined?的情況下,有無該條數(shù)據(jù)是沒有區(qū)別的,因為他們在表現(xiàn)形式上并無不同:
let?obj1?=?{?a:?undefined?}
let?obj2?=?{}
console.log(obj1.a)??//?undefined
console.log(obj2.a)??//?undefined
復制代碼
但需要注意的是,你可能在調(diào)用接口時,需要對?JSON?格式的數(shù)據(jù)中的?undefied?進行特殊處理。
為什么 let undefiend = 'test' 可以覆蓋掉 JavaScript 自身的 undefined?
JavaScript?對于?undefined?的限制方式為全局創(chuàng)建了一個只讀的?undefined?,但是并沒有徹底禁止局部?undefined?變量的定義。
據(jù)說在?JavaScript?高版本禁止了該操作,但我沒有準確的依據(jù)。
請在任何時候,都不要進行?undefined?變量的覆蓋,就算是你的?JSON?轉(zhuǎn)換將?undefined?轉(zhuǎn)換為?''?。也不要通過該操作進行,這將是及其危險的行為。
總結(jié)
關于使用 undefined 還是 null
這是一條公說公有理婆說婆有理的爭議內(nèi)容。
本人更傾向于使用?null?,因為這是顯示定義空值的方式。我并不能給出準確的理由。
但關于使用?undefined?我有一條建議:
如果你需要使用?undefined?定義空值,請不要采取以下兩種方式:
let a; let a = undefined;
進而采取下面這種方式顯式聲明?undefined?:
let a = void 0;
