Signatur
Beschreibung
Die for...in-Anweisung iteriert über alle enumerable String-Eigenschaften eines Objekts (wobei Eigenschaften mit Symbol-Schlüsseln ignoriert werden), einschließlich geerbter enumerable Eigenschaften.
Die Schleife iteriert über alle enumerable Eigenschaften des Objekts selbst sowie über jene, die das Objekt aus seiner prototype chain erbt (Eigenschaften näherer Prototypen haben Vorrang vor solchen von Prototypen, die weiter vom Objekt in seiner prototype chain entfernt sind).
Wie bei anderen Schleifen-Anweisungen kannst du innerhalb von statement Kontrollfluss-Anweisungen verwenden:
breakbeendet die Ausführung vonstatementund springt zur ersten Anweisung nach der Schleife.continuebeendet die Ausführung vonstatementund geht zur nächsten Iteration der Schleife über.
Eine for...in-Schleife iteriert nur über enumerable, nicht-Symbol-Eigenschaften. Objekte, die aus eingebauten Konstruktoren wie Array und Object erzeugt werden, haben geerbte nicht-enumerable Eigenschaften von Array.prototype und Object.prototype, wie etwa die indexOf()-Methode von Array oder die toString()-Methode von Object, die in der for...in-Schleife nicht besucht werden.
Die Reihenfolge der Traversierung ist seit der modernen ECMAScript-Spezifikation wohldefiniert und konsistent zwischen den Implementierungen. Innerhalb jeder Komponente der prototype chain werden zuerst alle nicht-negativen Integer-Schlüssel (jene, die Array-Indizes sein können) in aufsteigender Wertreihenfolge traversiert, danach die anderen String-Schlüssel in aufsteigender chronologischer Reihenfolge ihrer Erstellung.
Der variable-Teil von for...in akzeptiert alles, was vor dem =-Operator stehen kann. Du kannst const verwenden, um die Variable zu deklarieren, solange sie im Schleifenrumpf nicht neu zugewiesen wird (sie kann sich zwischen Iterationen ändern, da es sich um zwei separate Variablen handelt). Andernfalls kannst du let verwenden. Du kannst destructuring verwenden, um mehrere lokale Variablen zuzuweisen, oder einen Property-Accessor wie for (x.y in iterable), um den Wert einer Objekt-Eigenschaft zuzuweisen. using und await using sind jedoch nicht erlaubt, da die Variable immer ein String oder Symbol ist, während diese Deklarationen ein disposable Objekt erfordern.
Eine Legacy-Syntax erlaubt bei var-Deklarationen der Schleifenvariable einen Initialisierer. Diese wirft im strict mode einen syntax error und wird im non-strict mode ignoriert.
Gelöschte, hinzugefügte oder geänderte Eigenschaften
for...in besucht Property-Schlüssel folgendermaßen:
- Zuerst werden alle eigenen String-Schlüssel des aktuellen Objekts geholt, sehr ähnlich zu
Object.getOwnPropertyNames(). - Für jeden Schlüssel wird, falls kein String mit demselben Wert bereits besucht wurde, der Property-Descriptor abgerufen und die Eigenschaft nur besucht, wenn sie enumerable ist. Der Property-String wird jedoch als besucht markiert, auch wenn er nicht enumerable ist.
- Danach wird das aktuelle Objekt durch seinen Prototype ersetzt und der Prozess wiederholt.
Das bedeutet:
- Jede Eigenschaft, die während der Iteration zum aktuell besuchten Objekt hinzugefügt wird, wird nicht besucht, weil alle eigenen Eigenschaften des aktuellen Objekts bereits vorher gespeichert wurden.
- Wenn mehrere Objekte in der prototype chain eine Eigenschaft mit demselben Namen haben, wird nur die erste betrachtet, und sie wird nur besucht, wenn sie enumerable ist. Ist sie nicht enumerable, werden auch keine weiteren Eigenschaften mit demselben Namen weiter oben in der prototype chain besucht, selbst wenn diese enumerable sind.
Im Allgemeinen ist es am besten, während der Iteration keine Eigenschaften am Objekt hinzuzufügen, zu ändern oder zu entfernen — außer der Eigenschaft, die gerade besucht wird. Die Spezifikation erlaubt der Implementierung ausdrücklich, in einem der folgenden Fälle nicht dem obigen Algorithmus zu folgen:
- Die prototype chain des Objekts wird während der Iteration verändert.
- Eine Eigenschaft wird während der Iteration vom Objekt oder seiner prototype chain gelöscht.
- Eine Eigenschaft wird während der Iteration zur prototype chain des Objekts hinzugefügt.
- Die Enumerability einer Eigenschaft wird während der Iteration geändert.
In diesen Fällen können sich Implementierungen anders verhalten, als du erwartest, oder sogar untereinander unterschiedlich.
Array-Iteration und for...in
Array-Indizes sind einfach enumerable Eigenschaften mit Integer-Namen und ansonsten identisch mit allgemeinen Objekt-Eigenschaften. Die for...in-Schleife traversiert alle Integer-Schlüssel vor anderen Schlüsseln und in strikt aufsteigender Reihenfolge, wodurch sich das Verhalten von for...in der normalen Array-Iteration annähert. Die for...in-Schleife liefert jedoch alle enumerable Eigenschaften zurück, einschließlich jener mit nicht-Integer-Namen und geerbter Eigenschaften. Anders als for...of verwendet for...in Property-Enumeration statt des Array-iterators. In sparse arrays besucht for...of die leeren Slots, for...in jedoch nicht.
Es ist besser, eine for-Schleife mit numerischem Index, Array.prototype.forEach() oder die for...of-Schleife zu verwenden, da diese den Index als Zahl statt als String zurückgeben und nicht-Index-Eigenschaften vermeiden.
Nur eigene Eigenschaften iterieren
Wenn du nur die direkt am Objekt hängenden Eigenschaften betrachten willst und nicht die seiner Prototypen, kannst du eine der folgenden Techniken verwenden:
Object.keys()Object.getOwnPropertyNames()
Object.keys gibt eine Liste enumerable eigener String-Eigenschaften zurück, während Object.getOwnPropertyNames auch nicht-enumerable enthält.
Viele JavaScript-Styleguides und Linter raten von for...in ab, da es über die gesamte prototype chain iteriert — was selten das ist, was man will — und mit der verbreiteteren for...of-Schleife verwechselt werden kann. for...in ist am praktischsten für Debugging-Zwecke, als einfache Möglichkeit, die Eigenschaften eines Objekts zu überprüfen (durch Ausgabe an die Konsole o. Ä.). In Situationen, in denen Objekte als ad-hoc Key-Value-Paare verwendet werden, erlaubt for...in zu prüfen, ob einer dieser Schlüssel einen bestimmten Wert hält.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $variable | any | — | Erhält bei jeder Iteration einen String-Property-Namen. Kann entweder eine Deklaration mit const, let oder var sein, oder ein Zuweisungsziel (z. B. eine zuvor deklarierte Variable, eine Objekt-Eigenschaft oder ein destructuring pattern). Mit var deklarierte Variablen sind nicht lokal zur Schleife, d. h. sie liegen im selben Scope wie die for...in-Schleife. |
| $object | Object | — | Objekt, dessen nicht-Symbol enumerable Eigenschaften iteriert werden. |
| $statement | Statement | — | Eine Anweisung, die bei jeder Iteration ausgeführt wird. Kann variable referenzieren. Du kannst eine block statement verwenden, um mehrere Anweisungen auszuführen. |
Rückgabewert
for...in-Anweisung gibt keinen Wert zurück.Beispiele
for...in verwenden
const obj = { a: 1, b: 2, c: 3 };
for (const prop in obj) {
console.log(`obj.${prop} = ${obj[prop]}`);
}
// Logs:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"
Iteration eigener Eigenschaften
const triangle = { a: 1, b: 2, c: 3 };
function ColoredTriangle() {
this.color = "red";
}
ColoredTriangle.prototype = triangle;
const obj = new ColoredTriangle();
for (const prop in obj) {
if (Object.hasOwn(obj, prop)) {
console.log(`obj.${prop} = ${obj[prop]}`);
}
}
// Logs:
// "obj.color = red"
Nebenläufige Modifikation — Hinzugefügte Eigenschaften
const obj = { a: 1, b: 2 };
for (const prop in obj) {
console.log(`obj.${prop} = ${obj[prop]}`);
obj.c = 3;
}
// Logs:
// obj.a = 1
// obj.b = 2
Verschattete Eigenschaften
const proto = { a: 1 };
const obj = { __proto__: proto, a: 2 };
for (const prop in obj) {
console.log(`obj.${prop} = ${obj[prop]}`);
}
// Logs:
// obj.a = 2
Object.defineProperty(obj, "a", { enumerable: false });
for (const prop in obj) {
console.log(`obj.${prop} = ${obj[prop]}`);
}
// Logs nothing, because the first "a" property visited is non-enumerable.
Prototype während der Iteration ändern
const obj = { a: 1, b: 2 };
for (const prop in obj) {
console.log(`obj.${prop} = ${obj[prop]}`);
Object.setPrototypeOf(obj, { c: 3 });
}
Eigenschaft während der Iteration löschen
const obj = { a: 1, b: 2, c: 3 };
// Deleting a property before it is visited
for (const prop in obj) {
console.log(`obj.${prop} = ${obj[prop]}`);
delete obj.c;
}
const obj2 = { a: 1, b: 2, c: 3 };
// Deleting a property after it is visited
for (const prop in obj2) {
console.log(`obj2.${prop} = ${obj2[prop]}`);
delete obj2.a;
}
Enumerable Eigenschaften während der Iteration zum Prototype hinzufügen
const proto = {};
const obj = { __proto__: proto, a: 1, b: 2 };
for (const prop in obj) {
console.log(`obj.${prop} = ${obj[prop]}`);
proto.c = 3;
}
Enumerability einer Eigenschaft während der Iteration ändern
const obj = { a: 1, b: 2, c: 3 };
for (const prop in obj) {
console.log(`obj.${prop} = ${obj[prop]}`);
Object.defineProperty(obj, "c", { enumerable: false });
}