undefined und nullundefined vs. nullundefined und nullundefinednullundefined oder null??) für Standardwerte [ES2020]||) für Standardwerte??=) [ES2021]undefined und null haben keine Eigenschaftenundefined und nullViele Programmiersprachen haben einen "Nicht-Wert" namens null. Er zeigt an, dass eine Variable derzeit nicht auf ein Objekt verweist – zum Beispiel, wenn sie noch nicht initialisiert wurde.
Im Gegensatz dazu hat JavaScript zwei davon: undefined und null.
undefined vs. nullBeide Werte sind sehr ähnlich und werden oft austauschbar verwendet. Wie sie sich unterscheiden, ist daher subtil. Die Sprache selbst macht die folgende Unterscheidung:
undefined bedeutet "nicht initialisiert" (z.B. eine Variable) oder "nicht vorhanden" (z.B. eine Eigenschaft eines Objekts).null bedeutet "die absichtliche Abwesenheit eines beliebigen Objektwerts" (ein Zitat aus der Sprachspezifikation).Programmierer können die folgende Unterscheidung treffen:
undefined ist der Nicht-Wert, der von der Sprache verwendet wird (wenn etwas uninitialisiert ist usw.).null bedeutet "explizit ausgeschaltet". Das heißt, es hilft bei der Implementierung eines Typs, der sowohl sinnvolle Werte als auch einen Meta-Wert enthält, der für "kein sinnvoller Wert" steht. Ein solcher Typ wird in der funktionalen Programmierung als Option-Typ oder Maybe-Typ bezeichnet.undefined und nullDie folgenden Unterabschnitte beschreiben, wo undefined und null in der Sprache vorkommen. Wir werden mehreren Mechanismen begegnen, die später in diesem Buch ausführlicher erklärt werden.
undefinedUninitialisierte Variable myVar
let myVar;
assert.equal(myVar, undefined);Parameter x wurde nicht übergeben
function func(x) {
return x;
}
assert.equal(func(), undefined);Eigenschaft .unknownProp fehlt
const obj = {};
assert.equal(obj.unknownProp, undefined);Wenn wir das Ergebnis einer Funktion nicht explizit über eine return-Anweisung angeben, gibt JavaScript undefined für uns zurück.
function func() {}
assert.equal(func(), undefined);nullDer Prototyp eines Objekts ist entweder ein Objekt oder am Ende einer Prototypenkette steht null. Object.prototype hat keinen Prototyp.
> Object.getPrototypeOf(Object.prototype)
nullWenn wir einen regulären Ausdruck (wie /a/) mit einem String (wie 'x') abgleichen, erhalten wir entweder ein Objekt mit übereinstimmenden Daten (wenn der Abgleich erfolgreich war) oder null (wenn der Abgleich fehlschlug).
> /a/.exec('x')
nullDas JSON-Datenformat unterstützt undefined nicht, nur null.
> JSON.stringify({a: undefined, b: null})
'{"b":null}'undefined oder nullPrüfung auf beides
if (x === null) ···
if (x === undefined) ···Hat x einen Wert?
if (x !== undefined && x !== null) {
// ···
}
if (x) { // truthy?
// x is neither: undefined, null, false, 0, NaN, ''
}Ist x entweder undefined oder null?
if (x === undefined || x === null) {
// ···
}
if (!x) { // falsy?
// x is: undefined, null, false, 0, NaN, ''
}Truthy bedeutet "ist true, wenn zu einem booleschen Wert konvertiert". Falsy bedeutet "ist false, wenn zu einem booleschen Wert konvertiert". Beide Konzepte werden in §15.2 "Falsy und Truthy Werte" ausführlich erklärt.
??) für Standardwerte [ES2020]Manchmal erhalten wir einen Wert und möchten ihn nur verwenden, wenn er weder null noch undefined ist. Andernfalls möchten wir einen Standardwert als Fallback verwenden. Das können wir über den *Nullish Coalescing Operator* (??) tun.
const valueToUse = receivedValue ?? defaultValue;Die folgenden beiden Ausdrücke sind äquivalent.
a ?? b
a !== undefined && a !== null ? a : bDer folgende Code zeigt ein reales Beispiel:
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);Wenn es eine oder mehrere Übereinstimmungen für regex in str gibt, gibt .match() ein Array zurück. Wenn es keine Übereinstimmungen gibt, gibt es leider null zurück (und nicht das leere Array). Das beheben wir mit dem ??-Operator.
Wir hätten auch Optional Chaining verwenden können.
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)']);In einigen Fällen kann Destrukturierung auch für Standardwerte verwendet werden – zum Beispiel:
function getTitle(fileDesc) {
const {title = '(Untitled)'} = fileDesc;
return title;
}||) für StandardwerteVor ECMAScript 2020 und dem Nullish Coalescing Operator wurde das logische ODER für Standardwerte verwendet. Das hat einen Nachteil.
|| funktioniert wie erwartet für undefined und null.
> undefined || 'default'
'default'
> null || 'default'
'default'Aber es gibt auch für alle anderen falsy Werte den Standardwert zurück – zum Beispiel:
> false || 'default'
'default'
> 0 || 'default'
'default'
> 0n || 'default'
'default'
> '' || 'default'
'default'Vergleichen Sie das damit, wie ?? funktioniert:
> undefined ?? 'default'
'default'
> null ?? 'default'
'default'
> false ?? 'default'
false
> 0 ?? 'default'
0
> 0n ?? 'default'
0n
> '' ?? 'default'
''??=) [ES2021]??= ist ein logischer Zuweisungsoperator. Die folgenden beiden Ausdrücke sind grob äquivalent:
a ??= b
a ?? (a = b)Das bedeutet, dass ??= short-circuiting ist: Die Zuweisung erfolgt nur, wenn a undefined oder null ist.
??= zum Hinzufügen fehlender Eigenschaftenconst 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 und null haben keine Eigenschaftenundefined und null sind die einzigen beiden JavaScript-Werte, bei denen wir eine Ausnahme erhalten, wenn wir versuchen, eine Eigenschaft zu lesen. Um dieses Phänomen zu untersuchen, verwenden wir die folgende Funktion, die die Eigenschaft .foo liest ("holt") und das Ergebnis zurückgibt.
function getFoo(x) {
return x.foo;
}Wenn wir getFoo() auf verschiedene Werte anwenden, können wir sehen, dass es nur für undefined und null fehlschlägt.
> 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 und nullIn Java (das viele Aspekte von JavaScript inspiriert hat) hängen Initialisierungswerte vom statischen Typ einer Variablen ab:
null initialisiert.int-Variablen mit 0 initialisiert.In JavaScript kann jede Variable sowohl Objektwerte als auch primitive Werte speichern. Wenn null also "kein Objekt" bedeutet, benötigt JavaScript auch einen Initialisierungswert, der "weder Objekt noch primitiver Wert" bedeutet. Dieser Initialisierungswert ist undefined.
Quiz
Siehe Quiz-App.