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

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

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

前言

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

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

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

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

1.1 語義:自然的缺失

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

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

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

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

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

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

    1.     const user = { name: 'John' };
          console.log(user.age); // undefined
      
  3. 函數(shù)沒有返回值:如果一個函數(shù)沒有 return 語句,它默認(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 類型與注意事項

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

使用 typeof 運算符檢測 undefined 時,會準(zhǔn)確地返回 'undefined'

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

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

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

2.1 語義:主動的清空

undefined 相反,null 的核心語義是 “空值” 。它代表的是一種 “主動的清空”。

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

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

2.2 常見的使用場景

  1. 初始化對象變量

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

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

2.3 那個著名的 Bug:typeof null === 'object'

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

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

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

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

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

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

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

3.1 語義:無效的數(shù)字

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

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

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

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

這是因為 JavaScript 遵循了 IEEE 754 浮點數(shù)標(biāo)準(zhǔn),而 NaN 正是該標(biāo)準(zhǔn)中定義的一個特殊數(shù)值,用來表示非法的計算結(jié)果。

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

NaN 有兩個極其特殊的性質(zhì),也是無數(shù) bug 的來源:

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

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

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

3.3 如何正確檢測 NaN?

既然 === 不好使,那我們該怎么檢測一個值是不是 NaN 呢?

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

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

    •         console.log(Number.isNaN(NaN)); // true
              console.log(Number.isNaN('hello')); // false
              console.log(Number.isNaN(undefined)); // false
      
  • 利用自不等特性:這是一個古老的 trick,因為只有 NaN 才會不等于自己。

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

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

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

從表中可以清晰地看到,雖然它們在布爾轉(zhuǎn)換中都為 false,但在類型、語義和轉(zhuǎn)換行為上完全不同。

五、相等性判斷的迷局

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

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

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

null == undefined 必須返回 true。

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

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

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

if (value == null) {
    // 這會同時匹配 null 和 undefined
    // 等價于 if (value === null || value === undefined)
}

這在實際開發(fā)中非常常用,因為很多時候我們并不關(guān)心到底是 null 還是 undefined,我們只關(guān)心 “這個值是不是空的”。

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

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

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

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

Object.is() 是最嚴(yán)格的相等判斷,它不會做任何類型轉(zhuǎn)換,也不會對 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)格相等(===)下,各個特殊值之間的比較結(jié)果:

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

6.1 坑 1:濫用if (!value)

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

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

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

正確做法:明確檢查 nullundefined。

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

6.2 坑 2:JSON 序列化的丟失

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

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

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

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

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

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

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

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

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

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

  1. 語義優(yōu)先

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

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

    1. 使用空值合并運算符 ?? 來處理默認(rèn)值,它只會在 null/undefined 時生效,不會誤傷 0''。

      •         const count = response.count ?? 0;
        
    2. 使用可選鏈運算符 ?. 來安全訪問屬性,避免 Cannot read property of undefined 錯誤。

結(jié)語

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

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

理解了它們的區(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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

南通市| 邵阳市| 仁布县| 乌拉特中旗| 孟津县| 牙克石市| 长泰县| 禹城市| 天镇县| 嘉义市| 建湖县| 巨野县| 监利县| 原平市| 贵定县| 平罗县| 图们市| 平阴县| 盈江县| 育儿| 鹿邑县| 洛扎县| 福安市| 沅江市| 新晃| 九江市| 仙桃市| 六盘水市| 中卫市| 伽师县| 聂拉木县| 康马县| 云阳县| 南阳市| 海南省| 时尚| 陆良县| 大竹县| 沁阳市| 江永县| 苏尼特左旗|