DanLevy.net

Quiz: Destrukturierungsfreude

Bist du ein Destrukturierungs‑Meister?

Oder ist es deine Symphonie der Zerstörung?

Dieses Quiz prüft dein Wissen über Destructuring in JavaScript: von der „einfachen“ Objektsyntax über verschachteltes Destructuring bis hin zu Default‑Werten. Zusätzlich gibt es Bonusfragen zu TypeScript und Inline‑Typen!

Leg gleich mit dem Aufwärmen los – zeig, dass du Destructuring beherrschst! 👇

Was wird dieser Code ausgeben?

const person = {
name: 'Dan Levy',
location: 'Cape Town',
};
const { name, age } = person;
console.log(`Name: ${name}, Age: ${age}`);

Die Eigenschaft age existiert nicht auf person, also wird age undefined sein. Auf keinen Fall Infinity 😅

Das Ergebnis ist:

Name: Dan Levy, Age: undefined

Was macht dieser Code?

const person = [ 'Dan Levy', 'Cape Town' ];
const [ name, origin, age ] = person;
console.log(`Name: ${name}, Age: ${age}`);

Die Variable age ist im tuple‑Array nicht vorhanden, also wird sie undefined sein.

Das führt zu:

Name: Dan Levy, Age: undefined

Wie wäre es mit etwas verschachteltem Destructuring?

'use strict';
const person = {
name: { first: 'Dan' },
address: { city: 'Denver' },
};
const {
name: { first },
address: { city },
birth: { place },
} = person;
console.log(
`First: ${first}, City: ${place}`,
);

Die Eigenschaft birth: { place } existiert nicht auf person, daher wird ein Fehler ausgelöst. Eine Lösung ist, Standardwerte für verschachtelte Eigenschaften anzugeben.

Beim Zugriff auf verschachtelte Eigenschaften – sei vorsichtig – da die Fehler schwer zu erkennen sein können. Und Fehlermeldungen variieren zwischen Browsern und anderen Plattformen, was das Debuggen etwas schwieriger macht.

In modernem Chrome: TypeError: Cannot read properties of undefined (reading 'place')

In Node ist dies ebenfalls ein TypeError, weil JavaScript versucht, place aus undefined zu destrukturieren, bevor place überhaupt gelesen wird.

Der genaue Wortlaut variiert zwischen Browsern und Laufzeiten.

Jetzt mit ein paar Standardwerten, was passiert?

'use strict';
const person = {
name: { first: 'Dan' },
address: { city: 'Denver' },
};
const {
name: { first = 'Unknown' },
birth: { place = 'Unknown' },
} = person;
console.log(
`Hi ${first} from ${place}`,
);

Die Eigenschaft birth fehlt. JavaScript versucht deshalb, place aus undefined zu destrukturieren. Das löst einen Fehler aus, bevor der Standardwert für place greifen kann:

TypeError

Der genaue Meldungstext hängt von der Laufzeit ab. Ein Eigenschaftsstandard greift erst, wenn das umgebende Objekt verfügbar ist und die Eigenschaft fehlt oder undefined ist. Mit birth: { place = "Unknown" } = {} setzt du ein Standardobjekt ein, wenn birth selbst fehlt oder undefined ist.

Was wird das tun?

const person = {
name: { first: 'Dan' },
address: { city: 'Denver' },
};
const {
name: { first = 'Unknown' },
birth: { place = 'Unknown' } = {},
} = person;
console.log(
`Hi ${first} from ${place}`,
);

Die Eigenschaft birth existiert nicht auf person, also wird auf ein leeres Objekt = {} zurückgegriffen. Dadurch kann der Standardwert verwendet werden.

Was macht das jetzt als Funktionsparameter?

'use strict';
function displayUser({
name = "Unknown",
age = -1,
} = { place: "Unknown" }) {
console.log(`Hi ${name} from ${place}`);
}
displayUser({ name: "Dan" });

Diese Funktion extrahiert die Eigenschaften name und age und verwendet bei Bedarf Standardwerte. In diesem Fall ist der Schlüssel place im Default‑Objekt nur Rauschen, er wird in displayUser() nicht verwendet.

Der Strict‑Modus ändert daran nichts: Das Auslesen der nicht deklarierten Bindung place wirft einen ReferenceError.

Wie werden undefined‑Werte behandelt?

'use strict';
function displayPlace({
name = "N/A",
place = "N/A",
age = -1,
} = { place: "Unknown" }) {
console.log(`${place}`);
}
displayPlace({ name: "Dan" });
displayPlace({ name: "Dan", place: undefined });
displayPlace({ name: "Dan", place: "Joburg" });

Das Standardobjekt { place: "Unknown" } wird verwendet, wenn das Argument fehlt oder explizit undefined ist: Sowohl displayPlace() als auch displayPlace(undefined) geben Unknown aus.

Wird ein Objekt übergeben, verwendet eine fehlende oder auf undefined gesetzte Eigenschaft place den Eigenschaftsstandard "N/A". Parameter- und Eigenschaftsstandards greifen auf unterschiedlichen Ebenen.

Das Ergebnis ist:

displayPlace() // Unknown
displayPlace({ name: "Dan" }) // N/A
displayPlace({ name: "Dan", place: undefined }) // N/A

Ähnlich wie beim Vorherigen… Wie wird null behandelt?

function displayPlace({
name = "N/A",
place = "N/A",
age = -1,
} = { place: "Unknown" }) {
console.log(`${place}`);
}
displayPlace({ name: "Dan", place: null });
displayPlace({ name: "Dan", place: undefined });

In diesem Fall wird die Eigenschaft place beim ersten Aufruf auf null gesetzt und beim zweiten auf undefined. Der Eigenschaftsstandard "N/A" greift, wenn place fehlt oder undefined ist, auch bei einem übergebenen Objekt. null löst ihn nicht aus: Die Ausgaben sind null und N/A.

Jetzt kommt TypeScript

Jetzt in TypeScript… Was wird das tun?

'use strict';
function displayPlace(
{
name = 'N/A',
place = 'N/A',
}: {
name: string;
place: string;
age: number;
},
) {
console.log(`${place}`);
}
displayPlace({ name: 'Dan', place: null });

TypeScript meldet einen Fehler, weil place als string typisiert ist, aber der Aufruf null übergibt. Der Aufruf lässt außerdem die erforderliche Eigenschaft age weg.

Wenn du Typfehler ignorierst, wird beim Ausführen des Codes null in die Konsole ausgegeben.

Versuchen wir mal etwas Umbenennen/Zuweisung…

'use strict';
function displayPlace({
name = 'N/A',
place: location = 'N/A',
}: {
name: string;
place: string;
age?: number;
}) {
console.log(`${location}`);
}
displayPlace({ name: 'Dan', place: 'Denver' });

Dies gibt Denver in der Konsole aus. Die Eigenschaft place wird in der Funktionssignatur zu location umbenannt. Das ist ein gängiges Muster (Eigenschaften beim Destrukturieren umbenennen), wenn man Datenstrukturen von Drittanbietern anpasst.

Finde den Typfehler:

function greet({
name: {first = "N/A", last = "N/A"},
birth: {place = "N/A"} = {},
age = -1,
}: {
name: {first?: string, last?: string};
birth: {place?: string};
age: number;
}) {
console.log(`Hi ${first} ${last} from ${place}`);
}
greet({ name: {first: 'Dan'} });

Der Fehler liegt in der Signatur der greet‑Funktion. Die Eigenschaften age und birth fehlen im übergebenen Objekt, also sollten sie im Typdefinition optional sein.

Auch wenn die Eigenschaft birth mit einem Standardwert destrukturiert wird, verlangt die Typdefinition, dass sie vorhanden ist. Um eine Eigenschaft in TypeScript optional zu machen, sollte man den ?‑Operator verwenden.

Hinweis: birth?: { place?: string } ist nicht dasselbe wie birth: { place?: string } | undefined.

Jetzt mit Zuweisung (beachte die Variablen f, l und p)

'use strict';
function greet(
{
name: {first: f = "N/A", last: l = "N/A"},
birth: {place: p = "N/A"} = {},
age = -1,
}: {
name: {first?: string, last?: string};
birth?: {place?: string};
age?: number;
}
) {
console.log(`Hi ${f} ${l} from ${place}`);
// What will 👆 do?
}
greet({
name: {first: 'Dan', last: 'Levy'},
birth: {place: 'Cape Town'},
});

Ein weiterer Fehler! Du fängst an zu raten, oder?!

Es ist schwer, mehrere Ebenen von Destrukturierung mit Defaults, Zuweisungen und Typen zu lesen!

Sobald place der Variable p zugewiesen wird, ist sie im Scope der console.log‑Anweisung nicht mehr definiert.

console.log(`Hi ${f} ${l} from ${place}`); // ❌
// to:
console.log(`Hi ${f} ${l} from ${p}`); // ✅

Du willst noch mehr? Natürlich! In meiner Quiz-Sammlung findest du weitere Herausforderungen.