undefined
和 null
undefined
與 null
undefined
和 null
的發生
undefined
的發生null
的發生undefined
或 null
??
) [ES2020]
||
) 來設定預設值??=
) [ES2021]undefined
和 null
沒有屬性undefined
和 null
的歷史許多程式語言有一個稱為 null
的「非值」。它表示變數目前未指向物件,例如當它尚未初始化時。
相反地,JavaScript 有兩個:undefined
和 null
。
undefined
與 null
這兩個值非常相似,而且經常可以互換使用。因此,它們的差異很細微。語言本身做出了以下區分
undefined
表示「未初始化」(例如變數)或「不存在」(例如物件的屬性)。null
表示「任何物件值的故意遺漏」(引用自 語言規範)。程式設計師可能會做出以下區分
undefined
是語言中用來表示非值(當某個東西未初始化時,等等)。null
表示「明確關閉」。也就是說,它有助於實作一個包含有意義的值和一個代表「沒有有意義的值」的元值的類型。這種類型在函數式程式設計中稱為 選項類型或也許類型。undefined
和 null
的出現以下小節說明 undefined
和 null
在語言中出現的位置。我們會遇到幾種機制,這些機制會在本書後面的章節中做更詳細的說明。
undefined
的出現未初始化的變數 myVar
let myVar;
.equal(myVar, undefined); assert
未提供參數 x
function func(x) {
return x;
}.equal(func(), undefined); assert
缺少屬性 .unknownProp
const obj = {};
.equal(obj.unknownProp, undefined); assert
如果我們沒有透過 return
陳述式明確指定函式的結果,JavaScript 會幫我們傳回 undefined
function func() {}
.equal(func(), undefined); assert
null
的出現物件的原型不是物件,就是原型鏈的最後,null
。Object.prototype
沒有原型
> Object.getPrototypeOf(Object.prototype)null
如果我們將正規表示法(例如 /a/
)與字串(例如 'x'
)比對,我們會得到一個包含比對資料的物件(如果比對成功)或 null
(如果比對失敗)
> /a/.exec('x')null
JSON 資料格式 不支援 undefined
,只支援 null
> JSON.stringify({a: undefined, b: null})'{"b":null}'
undefined
或 null
檢查任一者
if (x === null) ···
if (x === undefined) ···
x
有值嗎?
if (x !== undefined && x !== null) {
// ···
}if (x) { // truthy?
// x is neither: undefined, null, false, 0, NaN, ''
}
x
是 undefined
或 null
嗎?
if (x === undefined || x === null) {
// ···
}if (!x) { // falsy?
// x is: undefined, null, false, 0, NaN, ''
}
真值表示「如果強制轉換為布林值,就是 true
」。假值表示「如果強制轉換為布林值,就是 false
」。這兩個概念在 §15.2「假值與真值」 中有適當的說明。
??
) [ES2020]有時候我們會收到一個值,而且只想要在它不是 null
或 undefined
時使用它。否則,我們想要使用預設值作為後備。我們可以透過空值合併運算子 (??
) 來做到這一點
const valueToUse = receivedValue ?? defaultValue;
以下兩個表達式是等效的
?? b
a !== undefined && a !== null ? a : b a
以下程式碼顯示一個實際範例
function countMatches(regex, str) {
const matchResult = str.match(regex); // null or Array
return (matchResult ?? []).length;
}
.equal(
assertcountMatches(/a/g, 'ababa'), 3);
.equal(
assertcountMatches(/b/g, 'ababa'), 2);
.equal(
assertcountMatches(/x/g, 'ababa'), 0);
如果 str
中有一個或多個與 regex
比對的結果,那麼 .match()
會傳回一個陣列。如果沒有比對結果,它很不幸地會傳回 null
(而不是空陣列)。我們透過 ??
運算子來修正這個問題。
我們也可以使用 選擇性串接
return matchResult?.length ?? 0;
function getTitle(fileDesc) {
return fileDesc.title ?? '(Untitled)';
}
const files = [
path: 'index.html', title: 'Home'},
{path: 'tmp.html'},
{;
].deepEqual(
assert.map(f => getTitle(f)),
files'Home', '(Untitled)']); [
在某些情況下,解構也可以用於預設值,例如
function getTitle(fileDesc) {
const {title = '(Untitled)'} = fileDesc;
return title;
}
||
) 作為預設值在 ECMAScript 2020 和空值合併運算子之前,邏輯或用於預設值。這有一個缺點。
||
對 undefined
和 null
的運作符合預期
> undefined || 'default''default'
> null || 'default''default'
但它也會為所有其他假值傳回預設值,例如
> false || 'default''default'
> 0 || 'default''default'
> 0n || 'default''default'
> '' || 'default''default'
將其與 ??
的運作方式進行比較
> undefined ?? 'default''default'
> null ?? 'default''default'
> false ?? 'default'false
> 0 ?? 'default'0
> 0n ?? 'default'0n
> '' ?? 'default'''
??=
) [ES2021]??=
是 邏輯賦值運算子。以下兩個表達式大致相等
??= b
a ?? (a = b) a
這表示 ??=
是 短路運算:只有當 a
為 undefined
或 null
時才會進行賦值。
??=
來新增遺失的屬性const books = [
{isbn: '123',
,
}
{title: 'ECMAScript Language Specification',
isbn: '456',
,
};
]
// Add property .title where it’s missing
for (const book of books) {
.title ??= '(Untitled)';
book
}
.deepEqual(
assert,
books
[
{isbn: '123',
title: '(Untitled)',
,
}
{title: 'ECMAScript Language Specification',
isbn: '456',
,
}; ])
undefined
和 null
沒有屬性undefined
和 null
是 JavaScript 中僅有的兩個值,如果我們嘗試讀取屬性,我們會得到一個例外。為了探討這個現象,我們使用以下函式,它讀取(「取得」)屬性 .foo
並傳回結果。
function getFoo(x) {
return x.foo;
}
如果我們將 getFoo()
套用於各種值,我們可以看到它只會對 undefined
和 null
失敗
> getFoo(undefined)TypeError: Cannot read properties of undefined (reading 'foo')
> getFoo(null)TypeError: Cannot read properties of null (reading 'foo')
> getFoo(true)undefined
> getFoo({})undefined
undefined
和 null
的歷史在 Java(啟發了 JavaScript 的許多方面)中,初始化值取決於變數的靜態類型
null
初始化。int
變數以 0
初始化。在 JavaScript 中,每個變數都可以同時儲存物件值和基本值。因此,如果 null
表示「不是物件」,JavaScript 也需要一個初始化值表示「既不是物件也不是基本值」。那個初始化值就是 undefined
。
測驗
請參閱 測驗應用程式。