Greifen Sie mithilfe einer Variablen dynamisch auf Objekteigenschaften zu

722

Ich versuche, mit einem dynamischen Namen auf eine Eigenschaft eines Objekts zuzugreifen. Ist das möglich?

const something = { bar: "Foobar!" };
const foo = 'bar';
something.foo; // The idea is to access something.bar, getting "Foobar!"
RichW
quelle

Antworten:

959

Es gibt zwei Möglichkeiten, auf Eigenschaften eines Objekts zuzugreifen :

  • Punktnotation: something.bar
  • Klammernotation: something['bar']

Der Wert zwischen den Klammern kann ein beliebiger Ausdruck sein. Wenn der Eigenschaftsname in einer Variablen gespeichert ist, müssen Sie daher die Klammernotation verwenden:

var foo = 'bar';
something[foo];
// both x = something[foo] and something[foo] = x work as expected
Jan Hančič
quelle
34
Vorsicht: Javascript-Compiler werden hier Fehler machen, da sie keine Zeichenfolgen umbenennen, aber Objekteigenschaften umbenennen
chacham15
6
Weitere Informationen dazu, warum dies möglich ist: JS-Objekte sind assoziative Arrays, deshalb. Weiterführende Literatur : quirksmode.org/js/associative.html stackoverflow.com/questions/14031368/…
Sudhanshu Mishra
@dotnetguy Nein, sind sie nicht. Arrays sind Objekte, die vom einfachen JS-Objektprototyp erben. Daher können Sie wie jedes einfache Objekt Eigenschaften hinzufügen. Das 'assoziative' Verhalten ist eher objektähnlich als Array-ähnlich. Sie können die 'assoziative' Version nicht durch einen einfachen Index iterieren, sodass kein Array-ähnliches Verhalten angezeigt wird. Sie können Ihr 'assoziatives' Array als {} oder [] definieren und es in beiden Fällen beim zufälligen Zugriff auf Eigenschaften gleich behandeln.
Besiegte Wombat
3
@VanquishedWombat Sie sind sich nicht sicher, worauf sich Ihr Einwand bezieht? Ich habe nicht gesagt, dass JS-Objekte Arrays sind?
Sudhanshu Mishra
1
Diese Antwort ist weit
überbewertet
104

Das ist meine Lösung:

function resolve(path, obj) {
    return path.split('.').reduce(function(prev, curr) {
        return prev ? prev[curr] : null
    }, obj || self)
}

Anwendungsbeispiele:

resolve("document.body.style.width")
// or
resolve("style.width", document.body)
// or even use array indexes
// (someObject has been defined in the question)
resolve("part.0.size", someObject) 
// returns null when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})
abahet
quelle
Hervorragende Antwort, siehe auch: stackoverflow.com/questions/37510640/…
Julian Knight
2
Sie haben mich dazu inspiriert, eine erweiterte Version zu erstellen, die Klammernotation und Eigenschaftsnamen mit Leerzeichen sowie die Überprüfung der Eingaben ermöglicht: it.knightnet.org.uk/kb/node-js/get-properties
Julian Knight
Ich liebe diese Lösung. Ich versuche jedoch, die Werte im Originalobjekt zu ändern. Es scheint, dass Ihre Funktion eine Unterkopie des Objekts zurückgibt. Ist es möglich, es so zu ändern, dass durch Ändern des zurückgegebenen Objekts das Original geändert wird?
Eagle1
40

In Javascript können wir zugreifen mit:

  • Punktnotation - foo.bar
  • eckige Klammern - foo[someVar]oderfoo["string"]

Der zweite Fall ermöglicht jedoch den dynamischen Zugriff auf Eigenschaften:

var foo = { pName1 : 1, pName2 : [1, {foo : bar }, 3] , ...}

var name = "pName"
var num  = 1;

foo[name + num]; // 1

// -- 

var a = 2;
var b = 1;
var c = "foo";

foo[name + a][b][c]; // bar
Sonique
quelle
4
Ich starre auf 2.000 Zeilen if-Anweisungen, weil der vorherige Entwickler keine eckigen Klammern verwendet und auf Objekteigenschaften statisch per Punktnotation zugegriffen hat. Es handelt sich um eine Genehmigungsprozess-App mit 7 verschiedenen Genehmigern, und die Schritte sind alle gleich. / rip
Chad
26

Im Folgenden finden Sie ein ES6-Beispiel dafür, wie Sie mit einem Eigenschaftsnamen, der durch Verketten von zwei Zeichenfolgen dynamisch generiert wurde, auf die Eigenschaft eines Objekts zugreifen können.

var suffix = " name";

var person = {
    ["first" + suffix]: "Nicholas",
    ["last" + suffix]: "Zakas"
};

console.log(person["first name"]);      // "Nicholas"
console.log(person["last name"]);       // "Zakas"

Dies wird als berechnete Eigenschaftsnamen bezeichnet

zloctb
quelle
16

Sie können dies auf verschiedene Arten erreichen.

let foo = {
    bar: 'Hello World'
};

foo.bar;
foo['bar'];

Die Klammernotation ist besonders leistungsfähig, da Sie auf eine Eigenschaft zugreifen können, die auf einer Variablen basiert:

let foo = {
    bar: 'Hello World'
};

let prop = 'bar';

foo[prop];

Dies kann erweitert werden, um jede Eigenschaft eines Objekts zu durchlaufen. Dies kann aufgrund neuerer JavaScript-Konstrukte wie ... von ... überflüssig erscheinen, hilft jedoch bei der Veranschaulichung eines Anwendungsfalls:

let foo = {
    bar: 'Hello World',
    baz: 'How are you doing?',
    last: 'Quite alright'
};

for (let prop in foo.getOwnPropertyNames()) {
    console.log(foo[prop]);
}

Sowohl die Punkt- als auch die Klammernotation funktionieren erwartungsgemäß auch für verschachtelte Objekte:

let foo = {
    bar: {
        baz: 'Hello World'
    }
};

foo.bar.baz;
foo['bar']['baz'];
foo.bar['baz'];
foo['bar'].baz;

Objektzerstörung

Wir könnten die Objektzerstörung auch als Mittel betrachten, um auf eine Eigenschaft in einem Objekt zuzugreifen, aber wie folgt:

let foo = {
    bar: 'Hello World',
    baz: 'How are you doing?',
    last: 'Quite alright'
};

let prop = 'last';
let { bar, baz, [prop]: customName } = foo;

// bar = 'Hello World'
// baz = 'How are you doing?'
// customName = 'Quite alright'
Gorka Hernandez
quelle
11

Sie können es so mit Lodash get machen

_.get(object, 'a[0].b.c');
Shalonteoh
quelle
Es gibt viele Situationen, z. B. die Suche nach tief verschachtelten Objekten, in denen dies die einzige Option ist.
Jonathan Kempf
8

AKTUALISIERT

Ich habe die folgenden Kommentare berücksichtigt und bin damit einverstanden. Eval ist zu vermeiden.

Der Zugriff auf Root-Eigenschaften in einem Objekt ist leicht zu erreichen obj[variable], aber das Verschachteln erschwert die Sache. Um nicht bereits geschriebenen Code zu schreiben, schlage ich vor, ihn zu verwenden lodash.get.

Beispiel

// Accessing root property
var rootProp = 'rootPropert';
_.get(object, rootProp, defaultValue);

// Accessing nested property
var listOfNestedProperties = [var1, var2];
_.get(object, listOfNestedProperties);

Lodash get kann auf verschiedene Arten verwendet werden. Hier finden Sie einen Link zur Dokumentation lodash.get

Herr Br
quelle
4
Vermeiden Sie es am besten, evalwenn immer möglich. stackoverflow.com/questions/86513/…
Luke
8
Die Verwendung evalfür etwas so Triviales wie den Zugriff auf Immobilien ist einfach übertrieben und unter keinen Umständen ratsam. Was ist "Ärger"? obj['nested']['test']funktioniert sehr gut und erfordert nicht, dass Sie Code in Zeichenfolgen einbetten.
Kyll
3
eval ist dreimal langsamer oder länger, ich würde dies Neulingen nicht empfehlen, da es ihnen schlechte Gewohnheiten beibringen könnte. Ich benutze obj['nested']['value']- erinnere dich an Kinder, Eval ist böse!
Jaggedsoft
1
@ Luke Er ist jetzt der einzige, der Lodash _.getan den Tisch bringen möchte . Ich denke, diese Antwort verdient jetzt positive Stimmen statt negative Stimmen. Es mag übertrieben sein, aber es ist gut zu wissen, dass es existiert.
Emile Bergeron
1
Vielen Dank, dass Sie lodash dafür eingeführt haben. Ich bin von Google hierher gekommen, um nach einer Methode zum Festlegen eines Werts tief in einem Objekt zu suchen, und habe deren _.set-Methode verwendet (die mit der obigen identisch ist, jedoch mit dem zusätzlichen Argument für den festzulegenden Wert).
TPHughes
5

Wann immer Sie dynamisch auf Eigenschaften zugreifen müssen, müssen Sie eine eckige Klammer verwenden, um auf Eigenschaften zuzugreifen, nicht auf "." Operator
Syntax: Objekt [Eigenschaft}

const something = { bar: "Foobar!" };
const foo = 'bar';
// something.foo; -- not correct way at it is expecting foo as proprty in  something={ foo: "value"};
// correct way is  something[foo]
alert( something[foo])

Rupesh Agrawal
quelle
4

Ich bin auf einen Fall gestoßen, in dem ich dachte, ich möchte die "Adresse" einer Objekteigenschaft als Daten an eine andere Funktion übergeben und das Objekt (mit AJAX) füllen, vom Adressarray nachschlagen und in dieser anderen Funktion anzeigen. Ich konnte die Punktnotation nicht verwenden, ohne String-Akrobatik zu betreiben, daher dachte ich, ein Array könnte stattdessen gut übergeben werden. Am Ende habe ich sowieso etwas anderes gemacht, schien aber mit diesem Beitrag verwandt zu sein.

Hier ist ein Beispiel eines Sprachdateiobjekts wie das, von dem ich Daten haben wollte:

const locs = {
  "audioPlayer": {
    "controls": {
      "start": "start",
      "stop": "stop"
    },
    "heading": "Use controls to start and stop audio."
  }
}

Ich wollte in der Lage sein, ein Array wie das folgende zu übergeben: ["audioPlayer", "control", "stop"], um auf den Sprachtext zuzugreifen, in diesem Fall "stop".

Ich habe diese kleine Funktion erstellt, die den "am wenigsten spezifischen" (ersten) Adressparameter nachschlägt und das zurückgegebene Objekt sich selbst neu zuweist. Dann ist es bereit, den nächstspezifischeren Adressparameter nachzuschlagen, falls einer vorhanden ist.

function getText(selectionArray, obj) {
  selectionArray.forEach(key => {
    obj = obj[key];
  });
  return obj;
}

Verwendungszweck:

/* returns 'stop' */
console.log(getText(["audioPlayer", "controls", "stop"], locs)); 

/* returns 'use controls to start and stop audio.' */
console.log(getText(["audioPlayer", "heading"], locs)); 
Luke
quelle
2

Es wird interessant, wenn Sie auch Parameter an diese Funktion übergeben müssen.

Code jsfiddle

var obj = {method:function(p1,p2,p3){console.log("method:",arguments)}}

var str = "method('p1', 'p2', 'p3');"

var match = str.match(/^\s*(\S+)\((.*)\);\s*$/);

var func = match[1]
var parameters = match[2].split(',');
for(var i = 0; i < parameters.length; ++i) {
  // clean up param begninning
    parameters[i] = parameters[i].replace(/^\s*['"]?/,'');
  // clean up param end
  parameters[i] = parameters[i].replace(/['"]?\s*$/,'');
}

obj[func](parameters); // sends parameters as array
obj[func].apply(this, parameters); // sends parameters as individual values
Jacksonkr
quelle
1

ES5 // Tief verschachtelte Variablen prüfen

Dieser einfache Code kann nach tief verschachtelten Variablen / Werten suchen, ohne dass jede Variable auf dem Weg überprüft werden muss ...

var getValue = function( s, context ){
    return Function.call( context || null, 'return ' + s )();
}

Ex. - eine tief verschachtelte Reihe von Objekten:

a = [ 
    {
      b : [
          {
             a : 1,
             b : [
                 {
                    c : 1,
                    d : 2   // we want to check for this
                 }
             ]
           }
      ]
    } 
]

Anstatt von :

if(a && a[0] && a[0].b && a[0].b[0] && a[0].b[0].b && a[0].b[0].b[0] && a[0].b[0].b[0].d && a[0].b[0].b[0].d == 2 )  // true

Wir können jetzt:

if( getValue('a[0].b[0].b[0].d') == 2 ) // true

Prost!


quelle
1
Wenn die Lösung darin besteht, eval zu verwenden, haben Sie gerade eine Million anderer Probleme erstellt.
Rodrigo Leite
@ RodrigoLeite ok, also wäre es kein Problem, mindestens eine zu geben ...
1
@ RodrigoLeite Ich habe es gelesen und die Lösung aktualisiert, um Functionstattdessen zu verwenden
0

Ich habe vor einiger Zeit eine Frage zu diesem Thema gestellt, und nach übermäßiger Recherche und dem Fehlen vieler Informationen, die hier sein sollten, habe ich das Gefühl, dass ich diesem älteren Beitrag etwas Wertvolles hinzufügen kann.

  • Zunächst möchte ich darauf eingehen, dass es verschiedene Möglichkeiten gibt, den Wert einer Eigenschaft abzurufen und in einer dynamischen Variablen zu speichern. Der erste beliebteste und einfachste Weg wäre meiner Meinung nach:
let properyValue = element.style['enter-a-property'];

Ich gehe diesen Weg jedoch selten, da er bei Eigenschaftswerten, die über Stylesheets zugewiesen wurden, nicht funktioniert. Um Ihnen ein Beispiel zu geben, werde ich mit ein bisschen Pseudocode demonstrieren.

 let elem = document.getElementById('someDiv');
 let cssProp = elem.style['width'];

Verwenden Sie das obige Codebeispiel. Wenn die width-Eigenschaft des div-Elements, das in der Variablen 'elem' gespeichert wurde, in einem CSS-Stylesheet und nicht in seinem HTML-Tag gestaltet wurde, erhalten Sie ohne Zweifel den Rückgabewert undefined, der darin gespeichert ist der Variablen cssProp. Der undefinierte Wert tritt auf, weil der in ein CSS-Stylesheet geschriebene Code berechnet werden muss, um den Wert zu erhalten, um den richtigen Wert zu erhalten. Sie müssen eine Methode verwenden, die den Wert der Eigenschaft berechnet, deren Wert im Stylesheet liegt.

  • Von nun an die Methode getComputedStyle ()!
function getCssProp(){
  let ele = document.getElementById("test");
  let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}

W3Schools getComputedValue Doc Dies ist ein gutes Beispiel, mit dem Sie spielen können. Dieser Link Mozilla CSS getComputedValue doc beschreibt jedoch ausführlich die Funktion getComputedValue und sollte von jedem aufstrebenden Entwickler gelesen werden, der sich mit diesem Thema nicht ganz auskennt.

  • Nebenbei bemerkt, die Methode getComputedValue wird nur abgerufen, nicht festgelegt. Dies ist natürlich ein großer Nachteil, es gibt jedoch eine Methode, die aus CSS-Stylesheets stammt und Werte festlegt, obwohl es sich nicht um Standard-Javascript handelt. Die JQuery-Methode ...
$(selector).css(property,value)

... bekommt und setzt. Es ist das, was ich benutze. Der einzige Nachteil ist, dass Sie JQuery kennengelernt haben, aber dies ist ehrlich gesagt einer der vielen guten Gründe, warum jeder Javascript-Entwickler JQuery lernen sollte. Es macht das Leben einfach und bietet Methoden wie diese ist mit Standard-Javascript nicht verfügbar. Hoffe das hilft jemandem !!!

Aft3rL1f3
quelle
0

Für alle, die den Wert einer verschachtelten Variablen festlegen möchten, gehen Sie wie folgt vor:

const _ = require('lodash'); //import lodash module

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// => 4

Dokumentation: https://lodash.com/docs/4.17.15#set

Außerdem Dokumentation, wenn Sie einen Wert erhalten möchten: https://lodash.com/docs/4.17.15#get

GavinBelson
quelle
-3

Sie sollten verwenden JSON.parse, werfen Sie einen Blick auf https://www.w3schools.com/js/js_json_parse.asp

const obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}')
console.log(obj.name)
console.log(obj.age)
onmyway133
quelle
-4
const something = { bar: "Foobar!" };
const foo = 'bar';

something[\`${foo}\`];
Sergey
quelle
7
Warum um alles in der Welt würdest du das tun? Ihr fooist bereits eine Zeichenfolge, `${foo}`ist also genau das gleiche wie foo. (Außerdem scheint Ihr Code einige zusätzliche Backslashes zu haben, die nicht dorthin gehören. Aber es wäre immer noch sinnlos, selbst wenn Sie diesen Syntaxfehler behoben hätten.)
Ilmari Karonen