BEARBEITEN : Alle folgenden Beispiele in dieser Antwort wurden so bearbeitet, dass sie eine neue Pfadvariable enthalten, die vom Iterator gemäß der Anforderung von @ supersan ausgegeben wird . Die Pfadvariable ist ein Array von Zeichenfolgen, wobei jede Zeichenfolge im Array jeden Schlüssel darstellt, auf den zugegriffen wurde, um zum resultierenden iterierten Wert aus dem ursprünglichen Quellobjekt zu gelangen. Die Pfadvariable kann in die get-Funktion / -Methode von lodash eingespeist werden . Oder Sie könnten Ihre eigene Version von lodashs get schreiben, die nur Arrays wie folgt verarbeitet:
function get (object, path) {
return path.reduce((obj, pathItem) => obj ? obj[pathItem] : undefined, object);
}
const example = {a: [1,2,3], b: 4, c: { d: ["foo"] }};
// these paths exist on the object
console.log(get(example, ["a", "0"]));
console.log(get(example, ["c", "d", "0"]));
console.log(get(example, ["b"]));
// these paths do not exist on the object
console.log(get(example, ["e", "f", "g"]));
console.log(get(example, ["b", "f", "g"]));
BEARBEITEN : Diese bearbeitete Antwort löst Endlosschleifen-Durchquerungen.
Stoppen von lästigen unendlichen Objektdurchquerungen
Diese bearbeitete Antwort bietet immer noch einen der zusätzlichen Vorteile meiner ursprünglichen Antwort, mit der Sie die bereitgestellte Generatorfunktion verwenden können, um eine sauberere und einfach iterierbare Schnittstelle zu verwenden (denken Sie an die Verwendung von for of
Schleifen, bei for(var a of b)
denen b
es sich um eine iterierbare und a
ein Element der iterierbaren handelt ). Durch die Verwendung hilft es auch , mit Wiederverwendung von Code die Generatorfunktion zusammen mit einer einfacheren api zu sein , indem sie es machen , so dass Sie müssen nicht die Iterationslogik wiederholen überall Sie Iterierte wollen tief auf die Eigenschaften eines Objekts und macht es auch möglich , sie break
aus die Schleife, wenn Sie die Iteration früher stoppen möchten.
Eine Sache, die mir auffällt und die nicht in meiner ursprünglichen Antwort enthalten ist, ist, dass Sie vorsichtig beliebige (dh "zufällige") Objekte durchlaufen sollten, da JavaScript-Objekte selbstreferenzierend sein können. Dies schafft die Möglichkeit, Endlosschleifen-Durchquerungen durchzuführen. Nicht geänderte JSON-Daten können sich jedoch nicht selbst referenzieren. Wenn Sie also diese bestimmte Teilmenge von JS-Objekten verwenden, müssen Sie sich keine Gedanken über Endlosschleifen-Durchläufe machen, und Sie können auf meine ursprüngliche Antwort oder andere Antworten verweisen. Hier ist ein Beispiel für eine nicht endende Durchquerung (beachten Sie, dass es sich nicht um einen ausführbaren Code handelt, da sonst die Registerkarte Ihres Browsers abstürzen würde).
Auch im Generatorobjekt in meinem bearbeiteten Beispiel habe ich mich für die Verwendung entschieden, Object.keys
anstatt for in
nur Nicht-Prototyp-Schlüssel für das Objekt zu iterieren. Sie können dies selbst austauschen, wenn Sie die Prototypschlüssel enthalten möchten. Siehe meinen ursprünglichen Antwortabschnitt unten für beide Implementierungen mit Object.keys
und for in
.
Schlimmer - Dies führt zu einer Endlosschleife für selbstreferenzielle Objekte:
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
// this self-referential property assignment is the only edited line
// from the below original example which makes the traversal
// non-terminating (i.e. it makes it infinite loop)
o.o = o;
function* traverse(o, path=[]) {
for (var i of Object.keys(o)) {
const itemPath = path.concat(i);
yield [i,o[i],itemPath];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* traverse(o[I], itemPath);
}
}
}
//that's all... no magic, no bloated framework
for(var [key, value, path] of traverse(o)) {
// do something here with each key and value
console.log(key, value, path);
}
Um sich davor zu schützen, können Sie einen Satz innerhalb eines Abschlusses hinzufügen, sodass die Funktion beim ersten Aufruf beginnt, einen Speicher für die Objekte zu erstellen, die sie gesehen hat, und die Iteration nicht fortsetzt, sobald sie auf ein bereits gesehenes Objekt stößt. Das folgende Code-Snippet macht das und behandelt somit Endlosschleifenfälle.
Besser - Dies führt nicht zu einer Endlosschleife für selbstreferenzielle Objekte:
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
// this self-referential property assignment is the only edited line
// from the below original example which makes more naive traversals
// non-terminating (i.e. it makes it infinite loop)
o.o = o;
function* traverse(o) {
const memory = new Set();
function * innerTraversal (o, path=[]) {
if(memory.has(o)) {
// we've seen this object before don't iterate it
return;
}
// add the new object to our memory.
memory.add(o);
for (var i of Object.keys(o)) {
const itemPath = path.concat(i);
yield [i,o[i],itemPath];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* innerTraversal(o[i], itemPath);
}
}
}
yield* innerTraversal(o);
}
console.log(o);
//that's all... no magic, no bloated framework
for(var [key, value, path] of traverse(o)) {
// do something here with each key and value
console.log(key, value, path);
}
Ursprüngliche Antwort
Eine neuere Möglichkeit, dies zu tun, wenn es Ihnen nichts ausmacht, den IE zu löschen und hauptsächlich aktuellere Browser zu unterstützen (überprüfen Sie die es6-Tabelle von kangax auf Kompatibilität). Hierfür können Sie es2015- Generatoren verwenden . Ich habe die Antwort von @ TheHippo entsprechend aktualisiert. Wenn Sie wirklich IE-Unterstützung wünschen, können Sie natürlich den babel JavaScript-Transpiler verwenden.
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
function* traverse(o, path=[]) {
for (var i in o) {
const itemPath = path.concat(i);
yield [i,o[i],itemPath];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* traverse(o[i], itemPath);
}
}
}
//that's all... no magic, no bloated framework
for(var [key, value, path] of traverse(o)) {
// do something here with each key and value
console.log(key, value, path);
}
Wenn Sie nur eigene aufzählbare Eigenschaften wünschen (im Grunde keine Eigenschaften einer Prototypkette), können Sie diese so ändern, dass sie stattdessen mit Object.keys
und einer for...of
Schleife iteriert werden :
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
function* traverse(o,path=[]) {
for (var i of Object.keys(o)) {
const itemPath = path.concat(i);
yield [i,o[i],itemPath];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* traverse(o[i],itemPath);
}
}
}
//that's all... no magic, no bloated framework
for(var [key, value, path] of traverse(o)) {
// do something here with each key and value
console.log(key, value, path);
}