Accedi dinamicamente alla proprietà dell'oggetto usando la variabile


Risposte:


959

Esistono due modi per accedere alle proprietà di un oggetto:

  • Notazione punto: something.bar
  • Notazione parentesi: something['bar']

Il valore tra parentesi può essere qualsiasi espressione. Pertanto, se il nome della proprietà è memorizzato in una variabile, è necessario utilizzare la notazione parentesi:

var foo = 'bar';
something[foo];
// both x = something[foo] and something[foo] = x work as expected

34
attenzione a questo: i compilatori javascript eseguiranno un errore qui poiché non rinominano le stringhe ma rinominano le proprietà dell'oggetto
chacham15

6
Qualche informazione in più sul perché questo è possibile: gli oggetti JS sono array associativi, ecco perché. Letture consigliate: quirksmode.org/js/associative.html stackoverflow.com/questions/14031368/...
Sudhanshu Mishra

@dotnetguy No, non lo sono. Le matrici sono oggetti che ereditano dal semplice prototipo di oggetto JS e quindi è possibile aggiungere proprietà un go-go come qualsiasi oggetto normale. Il comportamento "associativo" è più simile all'oggetto che alla matrice. Non è possibile iterare la versione "associativa" mediante un semplice indice, in modo che non mostri un comportamento simile a un array. Puoi definire il tuo array "associativo" come {} o [] e trattarlo allo stesso modo in entrambi i casi per quanto riguarda l'accesso casuale alle proprietà.
Sconfitto Wombat il

3
@VanquishedWombat Non sei sicuro di cosa riguarda la tua obiezione? Non ho detto che gli oggetti JS sono array?
Sudhanshu Mishra,

1
Questa risposta è troppo votata, non chiarisce nulla ...
Aft3rL1f3

104

Questa è la mia soluzione:

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

Esempi di utilizzo:

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'})


2
Mi hai ispirato a creare una versione migliorata che consenta la notazione tra parentesi e i nomi delle proprietà con spazi e la convalida degli input: it.knightnet.org.uk/kb/node-js/get-properties
Julian Knight

Adoro questa soluzione. Comunque sto provando a modificare i valori nell'oggetto originale, sembra che la tua funzione restituisca una sotto copia dell'oggetto. È possibile cambiarlo in modo che la modifica dell'oggetto restituito modifichi l'originale?
Eagle1,

40

In javascript possiamo accedere con:

  • notazione punto - foo.bar
  • parentesi quadre - foo[someVar]oppurefoo["string"]

Ma solo il secondo caso consente di accedere dinamicamente alle proprietà:

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

4
Sto fissando 2.000 righe di istruzioni if ​​perché lo sviluppatore precedente non ha utilizzato parentesi quadre e proprietà degli oggetti a accesso statico mediante notazione punto. È per un'app di processo di approvazione con 7 approvatori diversi e i passaggi sono tutti uguali. / rip
Ciad

26

Di seguito è riportato un esempio ES6 di come è possibile accedere alla proprietà di un oggetto utilizzando un nome di proprietà che è stato generato dinamicamente concatenando due stringhe.

var suffix = " name";

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

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

Questo si chiama nomi di proprietà calcolati


16

Puoi ottenerlo in diversi modi.

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

foo.bar;
foo['bar'];

La notazione parentesi è particolarmente potente in quanto consente di accedere a una proprietà in base a una variabile:

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

let prop = 'bar';

foo[prop];

Questo può essere esteso al ciclo su ogni proprietà di un oggetto. Questo può sembrare ridondante a causa di costrutti JavaScript più recenti come per ... di ..., ma aiuta a illustrare un caso d'uso:

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

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

Anche la notazione punto e parentesi funziona come previsto per gli oggetti nidificati:

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

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

Distruzione dell'oggetto

Potremmo anche considerare la distruzione degli oggetti come un mezzo per accedere a una proprietà in un oggetto, ma come segue:

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'

11

Puoi farlo in questo modo usando Lodash get

_.get(object, 'a[0].b.c');

Esistono molte situazioni, come le ricerche di oggetti nidificati in profondità, in cui questa è l'unica opzione.
Jonathan Kempf il

8

AGGIORNATO

Ho preso in considerazione i seguenti commenti e ho concordato. Eval deve essere evitato.

L'accesso alle proprietà della radice nell'oggetto è facilmente raggiungibile con obj[variable], ma l'annidamento complica la cosa. Non scrivere codice già scritto che consiglio di usare lodash.get.

Esempio

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

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

Lodash get può essere utilizzato in diversi modi, qui è presente il collegamento alla documentazione lodash.get


4
È meglio evitare di usarlo evalquando possibile. stackoverflow.com/questions/86513/…
Luca,

8
Usare evalqualcosa di banale come accedere alle proprietà è eccessivo e difficilmente consigliabile in qualsiasi circostanza. Che cos'è "guai"? obj['nested']['test']funziona molto bene e non richiede di incorporare il codice nelle stringhe.
Kyll,

3
eval è tre volte più lento o più, non lo consiglierei ai neofiti perché potrebbe insegnare loro cattive abitudini. Io uso obj['nested']['value']- ricorda i bambini, eval è malvagio!
jaggedsoft,

1
@Luke Ora è l'unico che vuole portare Lodash _.getal tavolo. Penso che questa risposta meriti adesso voti invece di voti negativi. Potrebbe essere eccessivo, ma è bene sapere che esiste.
Emile Bergeron,

1
Grazie per aver introdotto lodash per questo. Sono venuto qui da Google alla ricerca di un metodo per impostare un valore in profondità in un oggetto e ho usato il loro metodo _.set (che è identico a quello precedente ma con l'argomentazione aggiuntiva per il valore da impostare).
TPHughes

5

Ogni volta che devi accedere dinamicamente alla proprietà, devi usare la parentesi quadra per accedere alla proprietà non "." sintassi dell'operatore
: object [propery}

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])


4

Mi sono imbattuto in un caso in cui ho pensato voler passare l '"indirizzo" di una proprietà dell'oggetto come dati a un'altra funzione e popolare l'oggetto (con AJAX), cercare dall'array di indirizzi e visualizzarlo in quell'altra funzione. Non potevo usare la notazione a punti senza fare acrobazie a stringa, quindi pensavo che un array potesse essere bello da passare. Alla fine ho fatto qualcosa di diverso, ma mi è sembrato correlato a questo post.

Ecco un esempio di un oggetto file di lingua come quello da cui volevo i dati:

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

Volevo essere in grado di passare un array come: ["audioPlayer", "controlli", "stop"] per accedere al testo della lingua, "stop" in questo caso.

Ho creato questa piccola funzione che cerca il parametro "primo" (primo) indirizzo e riassegna l'oggetto restituito a se stesso. Quindi è pronto per cercare il parametro di indirizzo più specifico successivo se ne esiste uno.

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

utilizzo:

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

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

2

Diventa interessante anche quando devi passare parametri a questa funzione.

Codice 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

1

ES5 // Verifica variabili profondamente nidificate

Questo semplice pezzo di codice può verificare l'esistenza di variabili / valori profondamente nidificati senza dover controllare ogni variabile lungo il percorso ...

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

Ex. - una matrice di oggetti profondamente annidata:

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

Invece di :

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

Ora possiamo:

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

Saluti!


1
Se la soluzione è utilizzare eval, hai appena creato un milione di altri problemi.
Rodrigo Leite,

@RodrigoLeite ok, quindi non sarebbe un problema dare almeno uno ...


1
@RodrigoLeite ho letto, e aggiornato la soluzione di utilizzare Functioninvece

0

Ho fatto una domanda che in qualche modo è stata duplicata su questo argomento qualche tempo fa, e dopo un'eccessiva ricerca, e vedendo molte informazioni mancanti che dovrebbero essere qui, sento di avere qualcosa di prezioso da aggiungere a questo post più vecchio.

  • In primo luogo, desidero chiarire che esistono diversi modi per ottenere il valore di una proprietà e archiviarlo in una variabile dinamica. Il primo modo più popolare e più semplice di IMHO sarebbe:
let properyValue = element.style['enter-a-property'];

tuttavia raramente seguo questa strada perché non funziona sui valori delle proprietà assegnati tramite fogli di stile. Per fare un esempio, lo dimostrerò con un po 'di pseudo codice.

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

Utilizzando l'esempio di codice sopra; se la proprietà width dell'elemento div che è stato memorizzato nella variabile 'elem' è stata disegnata in un foglio di stile CSS e non all'interno del suo tag HTML, senza dubbio otterrai un valore di ritorno di un archivio non definito della variabile cssProp. Il valore indefinito si verifica perché per ottenere il valore corretto, al fine di ottenere il valore, il codice scritto all'interno di un foglio di stile CSS deve essere calcolato per ottenere il valore; è necessario utilizzare un metodo che calcolerà il valore della proprietà il cui valore si trova all'interno del foglio di stile.

  • D'ora in poi il metodo getComputedStyle ()!
function getCssProp(){
  let ele = document.getElementById("test");
  let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}

W3Schools getComputedValue Doc Questo fornisce un buon esempio e ti consente di giocarci, tuttavia, questo link Mozilla CSS getComputedValue doc parla in dettaglio della funzione getComputedValue e dovrebbe essere letto da qualsiasi aspirante sviluppatore che non sia del tutto chiaro su questo argomento.

  • Come nota a margine, ottiene solo il metodo getComputedValue, che non imposta. Questo, ovviamente, è un grande svantaggio, tuttavia esiste un metodo che deriva dai fogli di stile CSS, oltre a impostare valori, sebbene non sia Javascript standard. Il metodo JQuery ...
$(selector).css(property,value)

... ottiene e imposta. È quello che uso, l'unico aspetto negativo è che hai conosciuto JQuery, ma questo è onestamente uno dei tanti buoni motivi per cui ogni sviluppatore di Javascript dovrebbe imparare JQuery, semplifica la vita e offre metodi come questo, che non è disponibile con Javascript standard. Spero che questo aiuti qualcuno !!!




-4
const something = { bar: "Foobar!" };
const foo = 'bar';

something[\`${foo}\`];

7
Perché mai lo faresti? La tua fooè già una stringa, quindi `${foo}`è esattamente la stessa di foo. (Inoltre, il tuo codice sembra avere alcune barre rovesciate extra che non appartengono a questo. Ma sarebbe comunque inutile anche se correggessi l'errore di sintassi.)
Ilmari Karonen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.