undefined と nullundefined vs. nullundefined と null の出現undefined の出現null の出現undefined または null のチェック??)[ES2020]||)の利用??=)[ES2021]undefined と null はプロパティを持たないundefined と null の歴史多くのプログラミング言語には、null という1つの「非値」があります。これは、変数が現在オブジェクトを指していないことを示します。たとえば、まだ初期化されていない場合などです。
対照的に、JavaScriptには2つあります。undefined と null です。
undefined vs. null両方の値は非常に似ており、しばしば互換的に使用されます。したがって、それらの違いは微妙です。言語自体は、次の区別をしています。
undefined は「初期化されていない」(変数など)または「存在しない」(オブジェクトのプロパティなど)ことを意味します。null は「任意のオブジェクト値の意図的な欠落」(言語仕様からの引用)を意味します。プログラマーは次の区別をするかもしれません。
undefined は、(何かが初期化されていない場合などに)言語によって使用される非値です。null は「明示的にオフにされた」ことを意味します。つまり、意味のある値と「意味のある値がない」ことを表すメタ値の両方を含む型を実装するのに役立ちます。このような型は、関数型プログラミングではオプション型またはMaybe型と呼ばれます。undefined と null の出現次のサブセクションでは、言語内で undefined と null がどこに出現するかについて説明します。この本で後ほど詳しく説明するいくつかのメカニズムに出会うことになります。
undefined の出現未初期化の変数 myVar
let myVar;
assert.equal(myVar, undefined);パラメータ x が指定されていない
function func(x) {
return x;
}
assert.equal(func(), undefined);プロパティ .unknownProp が見つからない
const obj = {};
assert.equal(obj.unknownProp, undefined);return ステートメントを介して関数の結果を明示的に指定しない場合、JavaScriptは undefined を返します。
function func() {}
assert.equal(func(), undefined);null の出現オブジェクトのプロトタイプは、オブジェクトであるか、プロトタイプチェーンの最後では null です。Object.prototype にはプロトタイプがありません。
> Object.getPrototypeOf(Object.prototype)
null正規表現(/a/など)を文字列('x'など)に対してマッチングする場合、マッチングが成功した場合はマッチングデータを含むオブジェクトが得られるか、マッチングが失敗した場合は null が得られます。
> /a/.exec('x')
nullJSONデータ形式は、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, ''
}Truthy は「ブール値に強制変換された場合に true になる」ことを意味します。Falsy は「ブール値に強制変換された場合に false になる」ことを意味します。両方の概念は、§15.2「Falsyとtruthyな値」で適切に説明されています。
??)[ES2020]値を受け取って、それが null または undefined のどちらでもない場合にのみ使用したい場合があります。それ以外の場合は、フォールバックとしてデフォルト値を使用したいと思います。これは、Nullish coalescing演算子(??)を使用して行うことができます。
const valueToUse = receivedValue ?? defaultValue;次の2つの式は同等です。
a ?? b
a !== undefined && a !== null ? a : b次のコードは、実世界の例を示しています。
function countMatches(regex, str) {
const matchResult = str.match(regex); // null or Array
return (matchResult ?? []).length;
}
assert.equal(
countMatches(/a/g, 'ababa'), 3);
assert.equal(
countMatches(/b/g, 'ababa'), 2);
assert.equal(
countMatches(/x/g, 'ababa'), 0);str 内に regex の一致が1つ以上ある場合、.match() は配列を返します。一致がない場合、残念ながら(空の配列ではなく)null を返します。??演算子を使用して修正します。
オプショナルチェイニングを使用することもできました。
return matchResult?.length ?? 0;function getTitle(fileDesc) {
return fileDesc.title ?? '(Untitled)';
}
const files = [
{path: 'index.html', title: 'Home'},
{path: 'tmp.html'},
];
assert.deepEqual(
files.map(f => getTitle(f)),
['Home', '(Untitled)']);場合によっては、分割代入をデフォルト値に使用することもできます。たとえば、次のようになります。
function getTitle(fileDesc) {
const {title = '(Untitled)'} = fileDesc;
return title;
}||)の利用ECMAScript 2020以前およびNullish coalescing演算子以前は、論理ORがデフォルト値に使用されていました。これには欠点があります。
|| は undefined および null に対して期待どおりに動作します。
> undefined || 'default'
'default'
> null || 'default'
'default'しかし、他のすべてのfalsyな値に対してもデフォルトを返します。たとえば、次のようになります。
> 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]??= は論理代入演算子です。次の2つの式はほぼ同等です。
a ??= b
a ?? (a = b)つまり、??= はショートサーキットです。代入は、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) {
book.title ??= '(Untitled)';
}
assert.deepEqual(
books,
[
{
isbn: '123',
title: '(Untitled)',
},
{
title: 'ECMAScript Language Specification',
isbn: '456',
},
]);undefined と null はプロパティを持たないundefined と null は、プロパティを読み取ろうとした場合に例外が発生する唯一の2つの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({})
undefinedundefined と null の歴史(JavaScriptの多くの側面に影響を与えた)Javaでは、初期化値は変数の静的な型に依存します。
null で初期化されます。int 変数は 0 で初期化されます。JavaScriptでは、各変数はオブジェクト値とプリミティブ値の両方を保持できます。したがって、null が「オブジェクトではない」ことを意味する場合、JavaScriptには「オブジェクトでもプリミティブ値でもない」ことを意味する初期化値も必要です。その初期化値が undefined です。
クイズ
クイズアプリを参照してください。