688 Stimmen

Zugriff auf verschachtelte JavaScript-Objekte und -Arrays über einen String-Pfad

Ich habe eine Datenstruktur wie diese:

var someObject = {
    'part1' : {
        'name': 'Part 1',
        'size': '20',
        'qty' : '50'
    },
    'part2' : {
        'name': 'Part 2',
        'size': '15',
        'qty' : '60'
    },
    'part3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }, {
            'name': 'Part 3B',
            'size': '5',
            'qty' : '20'
        }, {
            'name': 'Part 3C',
            'size': '7.5',
            'qty' : '20'
        }
    ]
};

Und ich möchte mit diesen Variablen auf die Daten zugreifen:

var part1name = "part1.name";
var part2quantity = "part2.qty";
var part3name1 = "part3[0].name";

part1name sollte gefüllt werden mit someObject.part1.name Wert, der "Teil 1" ist. Dasselbe gilt für part2quantity, das mit 60 gefüllt ist.

Gibt es irgendwie zu erreichen dies entweder mit reinen Javascript oder JQuery?

0 Stimmen

Sie sind sich nicht sicher, was Sie hier fragen? Möchten Sie part1.name abfragen können und den Text "part1.name" zurückerhalten? Oder möchten Sie den in part1.name gespeicherten Wert abrufen?

0 Stimmen

Haben Sie versucht, etwas zu tun wie var part1name = someObject.part1name; `

1 Stimmen

@BonyT : Ich möchte someObject.part1.name abfragen und den Wert davon zurückgeben ("Part 1"). Ich möchte jedoch, dass die Abfrage (ich nannte sie "den Schlüssel") in einer Variablen 'part1name' gespeichert wird. Vielen Dank für Ihre Antwort. @3nigma : Das habe ich sicherlich. Aber das ist nicht meine Absicht. Vielen Dank für die Antwort.

12voto

Hogan Punkte 65759

Ich glaube, Sie wollen das hier:

var part1name = someObject.part1.name;
var part2quantity = someObject.part2.qty;
var part3name1 =  someObject.part3[0].name;

Das könnten Sie verlangen:

var part1name = someObject["part1"]["name"];
var part2quantity = someObject["part2"]["qty"];
var part3name1 =  someObject["part3"][0]["name"];

Beides wird funktionieren


Oder vielleicht fragen Sie nach dem hier

var partName = "part1";
var nameStr = "name";

var part1name = someObject[partName][nameStr];

Schließlich könnten Sie Folgendes verlangen

var partName = "part1.name";

var partBits = partName.split(".");

var part1name = someObject[partBits[0]][partBits[1]];

0 Stimmen

Ich glaube, OP fragt nach der letzten Lösung. Allerdings haben Strings nicht Split Methode, sondern vielmehr split .

0 Stimmen

Eigentlich habe ich die letzte Frage gestellt. Die partName-Variable wird mit einer Zeichenfolge gefüllt, die die Schlüsselstruktur angibt, die zu bewerten ist. Ihre Lösung scheint sinnvoll zu sein. Allerdings kann ich für erweiterte Tiefe in den Daten, wie 4-5 Ebene und mehr ändern müssen. Und ich frage mich, ob ich das Array und das Objekt einheitlich damit behandeln kann?

10voto

Dinesh Pandiyan Punkte 5243

Nur für den Fall, dass jemand im Jahr 2017 oder später auf diese Frage stößt und auf der Suche nach einem einprägsam Hier ist ein ausführlicher Blogbeitrag über Zugriff auf verschachtelte Objekte in JavaScript ohne sich von

Eigenschaft 'foo' von undefiniert kann nicht gelesen werden Fehler

Zugriff auf verschachtelte Objekte mit Array Reduce

Nehmen wir diese Beispielstruktur

const user = {
    id: 101,
    email: 'jack@dev.com',
    personalInfo: {
        name: 'Jack',
        address: [{
            line1: 'westwish st',
            line2: 'washmasher',
            city: 'wallas',
            state: 'WX'
        }]
    }
}

Um auf verschachtelte Arrays zugreifen zu können, können Sie Ihr eigenes Array reduce util schreiben.

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

// pass in your object structure as array elements
const name = getNestedObject(user, ['personalInfo', 'name']);

// to access nested array, just pass in array index as an element the path array.
const city = getNestedObject(user, ['personalInfo', 'address', 0, 'city']);
// this will return the city from the first address item.

Es gibt auch eine ausgezeichnete Minimalbibliothek für die Schriftverarbeitung typisch die all dies für Sie erledigt.

Mit typy sieht Ihr Code wie folgt aus

const city = t(user, 'personalInfo.address[0].city').safeObject;

Haftungsausschluss: Ich bin der Autor dieses Pakets.

10voto

Hashbrown Punkte 10248

Anstatt zu versuchen, JS-Syntax zu emulieren, die Sie haben, um einen Haufen von Compute Parsing zu verbringen, oder einfach falsch / vergessen Dinge wie eine Reihe von diesen Antworten (Schlüssel mit . ), verwenden Sie einfach ein Array von Schlüsseln.

var part1name     = Object.get(someObject, ['part1', 'name']);
var part2quantity = Object.get(someObject, ['part2', 'qty']);
var part3name1    = Object.get(someObject, ['part3', 0, 'name']);

answer

Wenn Sie stattdessen eine einzelne Zeichenkette verwenden müssen, können Sie diese einfach JSONifizieren.
Eine weitere Verbesserung dieser Methode besteht darin, dass Sie das Objekt der Stammebene löschen/einstellen können.

function resolve(obj, path) {
    let root = obj = [obj];
    path = [0, ...path];
    while (path.length > 1)
        obj = obj[path.shift()];
    return [obj, path[0], root];
}
Object.get = (obj, path) => {
    let [parent, key] = resolve(obj, path);
    return parent[key];
};
Object.del = (obj, path) => {
    let [parent, key, root] = resolve(obj, path);
    delete parent[key];
    return root[0];
};
Object.set = (obj, path, value) => {
    let [parent, key, root] = resolve(obj, path);
    parent[key] = value;
    return root[0];
};

Demo anderer Funktionen:
demonstration

Le site bob = for .set( / .del( ist nicht notwendig, es sei denn, der Pfad könnte leer sein (Manipulation des Root-Objekts).
Ich beweise, dass ich das Objekt nicht klone, indem ich steve einen Verweis auf das Original zu behalten und zu überprüfen bob == steve //true nach diesem ersten .set(

0 Stimmen

Es wird folgender Fehler angezeigt path is not iterable con Object.get .

4 Stimmen

In meinem Fall erhielt ich die Fehlermeldung, dass Object.get() keine Funktion ist.

8voto

James Wilkins Punkte 6123

Hier biete ich weitere Wege an, die in vielerlei Hinsicht schneller erscheinen:

Option 1: Zeichenkette aufteilen auf . oder [ oder ] oder ' oder ", umkehren, leere Elemente überspringen.

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var parts = path.split(/\[|\]|\.|'|"/g).reverse(), name; // (why reverse? because it's usually faster to pop off the end of an array)
    while (parts.length) { name=parts.pop(); if (name) origin=origin[name]; }
    return origin;
}

Option 2 (am schnellsten von allen, außer eval ): Zeichen-Scan auf niedriger Ebene (kein Regex/Split/etc, nur ein schneller Zeichen-Scan). Hinweis: Dieses Programm unterstützt keine Anführungszeichen für Indizes.

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var c = '', pc, i = 0, n = path.length, name = '';
    if (n) while (i<=n) ((c = path[i++]) == '.' || c == '[' || c == ']' || c == void 0) ? (name?(origin = origin[name], name = ''):(pc=='.'||pc=='['||pc==']'&&c==']'?i=n+2:void 0),pc=c) : name += c;
    if (i==n+2) throw "Invalid path: "+path;
    return origin;
} // (around 1,000,000+/- ops/sec)

Option 3: ( neu Option 2: erweitert um die Unterstützung von Anführungszeichen - etwas langsamer, aber immer noch schnell)

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var c, pc, i = 0, n = path.length, name = '', q;
    while (i<=n)
        ((c = path[i++]) == '.' || c == '[' || c == ']' || c == "'" || c == '"' || c == void 0) ? (c==q&&path[i]==']'?q='':q?name+=c:name?(origin?origin=origin[name]:i=n+2,name='') : (pc=='['&&(c=='"'||c=="'")?q=c:pc=='.'||pc=='['||pc==']'&&c==']'||pc=='"'||pc=="'"?i=n+2:void 0), pc=c) : name += c;
    if (i==n+2 || name) throw "Invalid path: "+path;
    return origin;
}

JSPerf: http://jsperf.com/ways-to-dereference-a-delimited-property-string/3

"eval(...)" ist aber immer noch der König (zumindest was die Leistung angeht). Wenn Sie Eigenschaftspfade direkt unter Ihrer Kontrolle haben, sollte es keine Probleme mit der Verwendung von "eval" geben (insbesondere, wenn Geschwindigkeit gewünscht ist). Wenn Eigenschaftspfade "über den Draht" gezogen werden ( auf der Linie !? lol :P), dann ja, verwenden Sie etwas anderes, um sicher zu sein. Nur ein Idiot würde sagen, dass man "eval" überhaupt nicht verwenden sollte, da es SIND gute Gründe wann er zu verwenden ist. Außerdem: "Es wird verwendet in Doug Crockfords JSON-Parser ." Wenn die Eingabe sicher ist, dann gibt es keine Probleme. Verwenden Sie das richtige Werkzeug für die richtige Aufgabe, das ist alles.

7voto

nesinervink Punkte 307

AngularJS

Speigg's Ansatz ist sehr ordentlich und sauber, obwohl ich diese Antwort bei der Suche nach der Lösung für den Zugriff auf AngularJS $scope Eigenschaften von String-Pfad gefunden und mit einer kleinen Änderung tut es den Job:

$scope.resolve = function( path, obj ) {
    return path.split('.').reduce( function( prev, curr ) {
        return prev[curr];
    }, obj || this );
}

Platzieren Sie diese Funktion einfach in Ihrem Root-Controller und verwenden Sie sie in jedem untergeordneten Bereich wie folgt:

$scope.resolve( 'path.to.any.object.in.scope')

0 Stimmen

Véase AngularJS hat $scope.$eval für eine andere Möglichkeit, dies mit AngularJS zu tun.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X