最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

前端JavaScript之NaN、undefined、null示例詳解

 更新時(shí)間:2026年05月28日 11:01:19   作者:淸湫  
我們?nèi)粘s開發(fā)中,你是不是經(jīng)常被undefined、null、NaN搞得暈頭轉(zhuǎn)向,下面這篇文章主要介紹了前端JavaScript之NaN、undefined、null的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

在 JavaScript 的世界里,有三個(gè)特殊的值常常讓初學(xué)者甚至有經(jīng)驗(yàn)的開發(fā)者感到困惑:undefined、nullNaN。它們都在某種程度上表示 “空” 或 “無(wú)值”,但在語(yǔ)義、類型系統(tǒng)以及運(yùn)行時(shí)行為上卻有著天壤之別。

很多線上 bug 的根源,往往就在于混淆了這三者的區(qū)別。比如,你是否曾疑惑過(guò)為什么 typeof null 會(huì)返回 'object'?為什么 NaN === NaN 會(huì)返回 false?為什么 null == undefinedtruenull === undefined 卻是 false

本文將帶你深入這三個(gè)特殊值的底層邏輯,拆解它們的產(chǎn)生場(chǎng)景、類型特征以及相等性判斷的陷阱,幫助你徹底理清這三者的關(guān)系,寫出更健壯的代碼。

一、undefined:系統(tǒng)的 “未定義”

1.1 語(yǔ)義:自然的缺失

undefined 的核心語(yǔ)義是 “未定義” 。它代表的是一種 “自然的缺失”—— 也就是說(shuō),當(dāng) JavaScript 引擎在找不到值的時(shí)候,它會(huì)默認(rèn)用 undefined 來(lái)填充。

這不是開發(fā)者主動(dòng)設(shè)置的,而是語(yǔ)言本身的默認(rèn)行為。當(dāng)一個(gè)變量聲明了但還沒賦值,或者訪問(wèn)了一個(gè)對(duì)象上不存在的屬性,JavaScript 并不會(huì)拋出錯(cuò)誤,而是返回 undefined 告訴你:“這里應(yīng)該有個(gè)值,但我還沒找到。”

1.2 常見的產(chǎn)生場(chǎng)景

undefined 通常出現(xiàn)在以下幾種情況:

  1. 變量聲明但未賦值:這是最常見的場(chǎng)景。

    1.     let name;
          console.log(name); // undefined
      
  2. 訪問(wèn)不存在的對(duì)象屬性

    1.     const user = { name: 'John' };
          console.log(user.age); // undefined
      
  3. 函數(shù)沒有返回值:如果一個(gè)函數(shù)沒有 return 語(yǔ)句,它默認(rèn)返回 undefined。

    1.     function doSomething() {
              // 沒有 return
          }
          console.log(doSomething()); // undefined
      
  4. 函數(shù)參數(shù)未傳參

    1.     function greet(name) {
              console.log(name); // undefined
          }
          greet(); // 沒傳參數(shù)
      

1.3 類型與注意事項(xiàng)

undefined 本身是一個(gè)獨(dú)立的原始數(shù)據(jù)類型(Undefined Type),它只有一個(gè)值,就是 undefined。

使用 typeof 運(yùn)算符檢測(cè) undefined 時(shí),會(huì)準(zhǔn)確地返回 'undefined'

let a;
console.log(typeof a); // 'undefined'

最佳實(shí)踐:不要主動(dòng)給變量賦值為 undefined。因?yàn)?undefined 是語(yǔ)言用來(lái)表示 “缺失” 的默認(rèn)值,如果你手動(dòng)賦值 let a = undefined,會(huì)混淆 “本來(lái)就沒有值” 和 “我故意把它清空了” 這兩種語(yǔ)義。如果你想表示清空,應(yīng)該使用 null。

二、null:開發(fā)者的 “空指針”

2.1 語(yǔ)義:主動(dòng)的清空

undefined 相反,null 的核心語(yǔ)義是 “空值” 。它代表的是一種 “主動(dòng)的清空”。

null 意味著:“我,開發(fā)者,明確地告訴引擎,這個(gè)變量現(xiàn)在是空的,它不指向任何對(duì)象。”

這是一個(gè)有意為之的狀態(tài)。通常我們用它來(lái)表示一個(gè)變量本來(lái)應(yīng)該是一個(gè)對(duì)象,但現(xiàn)在暫時(shí)沒有值。比如,在等待異步請(qǐng)求返回?cái)?shù)據(jù)之前,我們可以把變量初始化為 null,表示 “數(shù)據(jù)還沒加載好”。

2.2 常見的使用場(chǎng)景

  1. 初始化對(duì)象變量

    1.     // 表示用戶對(duì)象目前為空,等待后續(xù)賦值
          let currentUser = null;
      
          // 登錄成功后
          currentUser = { id: 1, name: 'John' };
      
  2. 主動(dòng)釋放引用:在一些手動(dòng)內(nèi)存管理的場(chǎng)景下,將對(duì)象引用置為 null 可以幫助垃圾回收。

    1.     let bigData = getBigData();
          // 處理完數(shù)據(jù)
          bigData = null; // 釋放引用
      
  3. 函數(shù)返回 “無(wú)結(jié)果” :當(dāng)查詢數(shù)據(jù)庫(kù)沒有找到結(jié)果時(shí),返回 null 而不是拋出錯(cuò)誤,表示 “找到了,但結(jié)果是空的”。

2.3 那個(gè)著名的 Bug:typeof null === 'object'

這是 JavaScript 中最廣為人知的歷史遺留問(wèn)題。當(dāng)你使用 typeof 檢測(cè) null 時(shí),你會(huì)得到:

console.log(typeof null); // 'object'

這其實(shí)是 JavaScript 最初實(shí)現(xiàn)時(shí)的一個(gè)錯(cuò)誤。在最初的 JavaScript 引擎中,值是由一個(gè)標(biāo)簽和實(shí)際數(shù)據(jù)表示的。對(duì)象的標(biāo)簽是 0,而 null 表示空指針,在大多數(shù)平臺(tái)下是空指針的引用也是 0x00,所以它的標(biāo)簽也被誤寫成了 0,導(dǎo)致 typeof 把它當(dāng)成了對(duì)象。

雖然這個(gè)錯(cuò)誤已經(jīng)被所有人知道了,但由于兼容性的原因,ECMAScript 標(biāo)準(zhǔn)一直沒有修復(fù)它。

因此,永遠(yuǎn)不要用 typeof 來(lái)檢測(cè) null ! 正確的檢測(cè)方式是直接使用嚴(yán)格相等:

if (value === null) {
    // 這才是正確的判斷方式
}

三、NaN:數(shù)字里的 “壞孩子”

3.1 語(yǔ)義:無(wú)效的數(shù)字

NaN 全稱是 Not-a-Number,即 “非數(shù)字”。但這并不意味著它的類型不是數(shù)字。恰恰相反,NaN 是一個(gè) 數(shù)值類型 的特殊值。

它的語(yǔ)義是:“這本來(lái)應(yīng)該是一個(gè)數(shù)字,但是運(yùn)算失敗了,所以我用 NaN 來(lái)表示這個(gè)無(wú)效的結(jié)果。”

比如,你試圖把一個(gè)字符串 "abc" 轉(zhuǎn)換成數(shù)字,或者對(duì)負(fù)數(shù)開平方,JavaScript 不會(huì)拋出異常,而是返回 NaN 來(lái)告訴你:“這次數(shù)字運(yùn)算搞砸了。”

console.log(typeof NaN); // 'number'
// 沒錯(cuò),它的類型是 number!

這是因?yàn)?JavaScript 遵循了 IEEE 754 浮點(diǎn)數(shù)標(biāo)準(zhǔn),而 NaN 正是該標(biāo)準(zhǔn)中定義的一個(gè)特殊數(shù)值,用來(lái)表示非法的計(jì)算結(jié)果。

3.2 最反直覺的特性:傳染性與自不等

NaN 有兩個(gè)極其特殊的性質(zhì),也是無(wú)數(shù) bug 的來(lái)源:

  1. 傳染性:只要你的數(shù)學(xué)運(yùn)算中混入了 NaN,那么最終的結(jié)果一定是 NaN。它就像病毒一樣會(huì)傳染。

    1.     console.log(1 + NaN); // NaN
          console.log(2 * NaN); // NaN
          console.log(Math.max(1, 2, NaN, 3)); // NaN
      
    2.   這意味著,一旦你的計(jì)算鏈中某個(gè)環(huán)節(jié)出錯(cuò)產(chǎn)生了 NaN,它會(huì)一路污染到最終結(jié)果,而且很難定位到底是哪里出的錯(cuò)。
  2. 它不等于任何值,包括它自己:這是最反直覺的一點(diǎn)。

    1.     console.log(NaN === NaN); // false
          console.log(NaN == NaN); // false
      
    2.   為什么會(huì)這樣?因?yàn)?IEEE 754 標(biāo)準(zhǔn)規(guī)定,NaN 不與任何值相等,包括它自己。這是為了讓你能通過(guò) x !== x 來(lái)檢測(cè) NaN

3.3 如何正確檢測(cè) NaN?

既然 === 不好使,那我們?cè)撛趺礄z測(cè)一個(gè)值是不是 NaN 呢?

  • 全局的 isNaN() :這是最早的方法,但它有坑。它會(huì)先把參數(shù)轉(zhuǎn)換成數(shù)字,如果轉(zhuǎn)換失敗就返回 true。這意味著它會(huì)把很多非數(shù)字的值也誤判為 NaN

    •         console.log(isNaN('hello')); // true!因?yàn)?'hello' 轉(zhuǎn)數(shù)字失敗了
              console.log(isNaN(undefined)); // true
      
    •   這顯然不對(duì),因?yàn)?'hello' 本身并不是 NaN,它只是個(gè)字符串。
  • Number.isNaN() :ES6 引入的正確方法。它不會(huì)做類型轉(zhuǎn)換,只有當(dāng)值真的是 NaN 時(shí)才返回 true

    •         console.log(Number.isNaN(NaN)); // true
              console.log(Number.isNaN('hello')); // false
              console.log(Number.isNaN(undefined)); // false
      
  • 利用自不等特性:這是一個(gè)古老的 trick,因?yàn)橹挥?NaN 才會(huì)不等于自己。

    •         function myIsNaN(value) {
                  return value !== value;
              }
      

四、一張表看懂三者的區(qū)別

為了讓你更直觀地對(duì)比這三者的區(qū)別,我們整理了一張核心特性對(duì)比表:

從表中可以清晰地看到,雖然它們?cè)诓紶栟D(zhuǎn)換中都為 false,但在類型、語(yǔ)義和轉(zhuǎn)換行為上完全不同。

五、相等性判斷的迷局

搞清楚了它們各自的定義,接下來(lái)最容易踩坑的就是相等性判斷了。JavaScript 提供了三種比較方式:==、===Object.is(),它們對(duì)這三個(gè)值的處理各不相同。

5.1 == vs ===:null 和 undefined 的曖昧關(guān)系

我們都知道 == 會(huì)進(jìn)行類型轉(zhuǎn)換,而 === 不會(huì)。對(duì)于 nullundefined,ECMAScript 標(biāo)準(zhǔn)做了一個(gè)特殊的規(guī)定:

null == undefined 必須返回 true

這是因?yàn)檎Z(yǔ)言設(shè)計(jì)者認(rèn)為,這兩者都表示 “無(wú)值”,在寬松比較下應(yīng)該被視為相等。但在嚴(yán)格比較下,它們是不同的。

console.log(null == undefined);  // true
console.log(null === undefined); // false

這就導(dǎo)致了一個(gè)非常有用的簡(jiǎn)寫技巧:如果你想同時(shí)檢查一個(gè)變量是不是 null 或者 undefined,你可以直接寫:

if (value == null) {
    // 這會(huì)同時(shí)匹配 null 和 undefined
    // 等價(jià)于 if (value === null || value === undefined)
}

這在實(shí)際開發(fā)中非常常用,因?yàn)楹芏鄷r(shí)候我們并不關(guān)心到底是 null 還是 undefined,我們只關(guān)心 “這個(gè)值是不是空的”。

5.2Object.is:終極的相等判斷

ES6 引入了 Object.is() 方法,它解決了 === 無(wú)法處理 NaN 的問(wèn)題。

我們來(lái)看一下三種比較方式的區(qū)別:

比較=====Object.is()
null == undefinedtruefalsefalse
NaN == NaNfalsefalsetrue
+0 == -0truetruefalse

Object.is() 是最嚴(yán)格的相等判斷,它不會(huì)做任何類型轉(zhuǎn)換,也不會(huì)對(duì) NaN-0 做特殊處理。

console.log(Object.is(NaN, NaN)); // true!終于可以正常判斷 NaN 了
console.log(Object.is(null, null)); // true
console.log(Object.is(undefined, undefined)); // true

下面的矩陣圖展示了在嚴(yán)格相等(===)下,各個(gè)特殊值之間的比較結(jié)果:

六、實(shí)戰(zhàn)避坑:那些年我們踩過(guò)的雷

6.1 坑 1:濫用if (!value)

很多人喜歡用 if (!value) 來(lái)判斷變量是否為空。但這會(huì)把所有的假值(Falsy Value)都過(guò)濾掉,包括 0、''、false。

// 錯(cuò)誤示范
function processAge(age) {
    if (!age) {
        console.log('年齡為空');
    } else {
        console.log('處理年齡', age);
    }
}

processAge(0); // 錯(cuò)誤!0 是合法年齡,但被當(dāng)成空了

正確做法:明確檢查 nullundefined。

if (age == null) {
    console.log('年齡為空');
}

6.2 坑 2:JSON 序列化的丟失

當(dāng)你使用 JSON.stringify 序列化數(shù)據(jù)時(shí),undefinedNaNInfinity 會(huì)被特殊處理:

  • undefined、函數(shù)、Symbol 會(huì)被忽略(在對(duì)象中)或者變成 null(在數(shù)組中)
  • NaNInfinity 會(huì)變成 null
JSON.stringify({ a: NaN, b: undefined, c: null });
// 結(jié)果: "{"a":null,"c":null}"

注意,這里 NaNundefined 都變成了 null!這意味著你序列化之后,就再也分不清原來(lái)的是 NaN 還是 undefined 還是 null 了,這在處理后端數(shù)據(jù)時(shí)要格外小心。

6.3 坑 3:默認(rèn)參數(shù)只對(duì) undefined 生效

ES6 的默認(rèn)參數(shù)只有在參數(shù)是 undefined 的時(shí)候才會(huì)觸發(fā),null 不會(huì)!

function greet(name = 'Guest') {
    console.log(name);
}

greet(undefined); // Guest (觸發(fā)默認(rèn)值)
greet(null);      // null (不觸發(fā)!因?yàn)?null 是一個(gè)明確的傳值)

這也符合語(yǔ)義:undefined 表示 “我沒傳這個(gè)參數(shù)”,而 null 表示 “我傳了,就是空”。

七、最佳實(shí)踐總結(jié)

經(jīng)過(guò)上面的分析,我們可以總結(jié)出一套最佳實(shí)踐,幫助你在日常開發(fā)中正確使用這三個(gè)值:

  1. 語(yǔ)義優(yōu)先

    1. undefined 處理 “缺失” 的情況,不要手動(dòng)賦值它。
    2. null 表示 “主動(dòng)清空”,當(dāng)你想表示一個(gè)對(duì)象變量為空時(shí)使用它。
  2. 判斷準(zhǔn)則

    1. 檢測(cè) null:使用 value === null
    2. 檢測(cè) undefined:使用 value === undefined 或者 typeof value === 'undefined'(處理未聲明變量)
    3. 檢測(cè) NaN:使用 Number.isNaN(value),永遠(yuǎn)不要用全局的 isNaN()
    4. 同時(shí)檢測(cè)兩者:使用 value == null 來(lái)同時(shí)匹配 nullundefined,這是一個(gè)安全的簡(jiǎn)寫。
  3. 利用現(xiàn)代語(yǔ)法

    1. 使用空值合并運(yùn)算符 ?? 來(lái)處理默認(rèn)值,它只會(huì)在 null/undefined 時(shí)生效,不會(huì)誤傷 0''

      •         const count = response.count ?? 0;
        
    2. 使用可選鏈運(yùn)算符 ?. 來(lái)安全訪問(wèn)屬性,避免 Cannot read property of undefined 錯(cuò)誤。

結(jié)語(yǔ)

undefinednullNaN,這三個(gè)看似簡(jiǎn)單的值,背后卻隱藏著 JavaScript 類型系統(tǒng)的設(shè)計(jì)哲學(xué)和歷史包袱。

  • undefined 是系統(tǒng)告訴你 “這里沒東西”。
  • null 是你告訴系統(tǒng) “這里我故意清空了”。
  • NaN 是系統(tǒng)告訴你 “數(shù)字運(yùn)算炸了”。

理解了它們的區(qū)別,你就能在日常開發(fā)中避開絕大多數(shù)與空值相關(guān)的 bug,寫出更清晰、更健壯的前端代碼。

參考資料

  1. MDN Web Docs. NaN
  2. MDN Web Docs. undefined
  3. MDN Web Docs. Object.is()
  4. MDN Web Docs. 相等比較和相同
  5. OpenReplay. The Strange Life of NaN in JavaScript

到此這篇關(guān)于前端JavaScript之NaN、undefined、null的文章就介紹到這了,更多相關(guān)JS NaN、undefined、null內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

环江| 岳普湖县| 宝丰县| 芒康县| 安岳县| 崇信县| 莆田市| 邵阳县| 青海省| 凌源市| 岐山县| 石嘴山市| 辛集市| 怀安县| 韩城市| 浦县| 龙岩市| 河间市| 鲁甸县| 定南县| 贵德县| 贵定县| 文成县| 罗城| 铜梁县| 无极县| 荣昌县| 乡宁县| 天柱县| 芮城县| 修水县| 琼结县| 搜索| 屏山县| 桃园县| 太康县| 浪卡子县| 泗洪县| 青神县| 曲麻莱县| 商城县|