Acceder dinámicamente a la propiedad del objeto usando la variable

Respuestas:

959

Hay dos formas de acceder a las propiedades de un objeto:

  • Notación de puntos: something.bar
  • Notación de soporte: something['bar']

El valor entre paréntesis puede ser cualquier expresión. Por lo tanto, si el nombre de la propiedad se almacena en una variable, debe usar la notación de paréntesis:

var foo = 'bar';
something[foo];
// both x = something[foo] and something[foo] = x work as expected
Jan Hančič
fuente
34
tenga cuidado con esto: los compiladores de JavaScript producirán un error aquí, ya que no
cambian el
66
Más información sobre por qué esto es posible: los objetos JS son matrices asociativas, por eso. Lecturas adicionales: quirksmode.org/js/associative.html stackoverflow.com/questions/14031368/…
Sudhanshu Mishra
@dotnetguy No, no lo son. Las matrices son objetos que heredan del prototipo de objeto JS simple y, por lo tanto, puede agregar propiedades como un objeto normal. El comportamiento 'asociativo' es más parecido a un objeto que a una matriz. No puede iterar la versión 'asociativa' por un índice simple, por lo que no muestra un comportamiento tipo matriz. Puede definir su matriz 'asociativa' como {} o [] y tratarla de la misma manera en cualquier caso en lo que respecta al acceso a propiedades aleatorias.
Wombat vencido el
3
@VanquishedWombat ¿No está seguro de a qué se refiere su objeción? ¿No dije que los objetos JS son matrices?
Sudhanshu Mishra
1
Esta respuesta está muy votada, no aclara nada ...
Aft3rL1f3
104

Esta es mi solución:

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

Ejemplos de uso:

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
fuente
Excelente respuesta, vea también: stackoverflow.com/questions/37510640/…
Julian Knight
2
Me inspiró a crear una versión mejorada que permita la notación de corchetes y nombres de propiedades con espacios, así como validar las entradas: it.knightnet.org.uk/kb/node-js/get-properties
Julian Knight
Amo esta solución Sin embargo, estoy tratando de modificar los valores en el objeto original, parece que su función devuelve una copia secundaria del objeto. ¿Es posible cambiarlo para que la modificación del objeto devuelto modifique el original?
Eagle1
40

En javascript podemos acceder con:

  • notación de puntos foo.bar
  • corchetes - foo[someVar]ofoo["string"]

Pero solo el segundo caso permite acceder a las propiedades dinámicamente:

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
fuente
44
Estoy mirando 2.000 líneas de sentencias if porque el desarrollador anterior no usó corchetes y las propiedades de objetos con acceso estático por notación de puntos. Es para una aplicación de proceso de aprobación que tiene 7 aprobadores diferentes y los pasos son todos iguales. / rip
Chad
26

El siguiente es un ejemplo de ES6 de cómo puede acceder a la propiedad de un objeto utilizando un nombre de propiedad que se ha generado dinámicamente mediante la concatenación de dos cadenas.

var suffix = " name";

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

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

Esto se llama nombres de propiedades calculadas

zloctb
fuente
16

Puede lograr esto de muchas maneras diferentes.

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

foo.bar;
foo['bar'];

La notación de corchetes es especialmente poderosa ya que le permite acceder a una propiedad basada en una variable:

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

let prop = 'bar';

foo[prop];

Esto se puede extender al bucle sobre cada propiedad de un objeto. Esto puede parecer redundante debido a las nuevas construcciones de JavaScript, como para ... de ..., pero ayuda a ilustrar un caso de uso:

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

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

La notación de punto y paréntesis también funciona como se espera para los objetos anidados:

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

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

Desestructuración de objetos

También podríamos considerar la desestructuración de objetos como un medio para acceder a una propiedad en un objeto, pero de la siguiente manera:

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 Hernández
fuente
11

Puedes hacerlo así usando Lodash get

_.get(object, 'a[0].b.c');
shalonteoh
fuente
Hay muchas situaciones, como búsquedas de objetos anidados profundos, donde esta es la única opción.
Jonathan Kempf
8

ACTUALIZADO

He tenido en cuenta los comentarios a continuación y acepto. Eval debe ser evitado.

Acceder a las propiedades raíz en el objeto se logra fácilmente con obj[variable], pero anidarse complica las cosas. No escribir código ya escrito que sugiero usar lodash.get.

Ejemplo

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

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

Lodash get se puede usar de diferentes maneras, aquí hay un enlace a la documentación lodash.get

Sr. Br
fuente
44
Es mejor evitar usar evalsiempre que sea posible. stackoverflow.com/questions/86513/…
Luke
8
Usar evalpara algo tan trivial como acceder a las propiedades es simplemente excesivo y difícilmente aconsejable bajo ninguna circunstancia. ¿Qué es "problema"? obj['nested']['test']funciona muy bien y no requiere que incruste código en cadenas.
Kyll
3
eval es tres veces más lento o más, no recomendaría esto a los novatos porque podría enseñarles malos hábitos. Yo uso obj['nested']['value']- recuerda niños, eval es malvado!
jaggedsoft
1
@Luke Ahora es el único que quiere traer a Lodash _.geta la mesa. Creo que esta respuesta merece ahora votos positivos en lugar de votos negativos. Puede ser excesivo, pero es bueno saber que existe.
Emile Bergeron
1
Gracias por presentar lodash por esto. Vine aquí por google buscando un método para establecer un valor profundo en un objeto, y usé su método _.set (que es idéntico al anterior pero con el argumento adicional de que el valor se establezca).
TPHughes
5

Siempre que necesite acceder a la propiedad dinámicamente, debe usar corchetes para acceder a la propiedad no ". operador
Sintaxis: objeto [propiedad}

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
fuente
4

Encontré un caso en el que pensé que quería pasar la "dirección" de una propiedad de objeto como datos a otra función y llenar el objeto (con AJAX), buscar desde la matriz de direcciones y mostrar esa otra función. No podía usar la notación de puntos sin hacer acrobacias de cadena, así que pensé que sería bueno pasar una matriz. Terminé haciendo algo diferente de todos modos, pero parecía relacionado con esta publicación.

Aquí hay una muestra de un objeto de archivo de idioma como el que quería datos:

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

Quería poder pasar una matriz como: ["audioPlayer", "controles", "detener"] para acceder al texto del idioma, "detener" en este caso.

Creé esta pequeña función que busca el parámetro de dirección "menos específico" (primero) y reasigna el objeto devuelto a sí mismo. Entonces está listo para buscar el siguiente parámetro de dirección más específico si existe.

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

uso:

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

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

Se pone interesante cuando tienes que pasar parámetros a esta función también.

Código 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
fuente
1

ES5 // Comprobar variables profundamente anidadas

Este simple código puede verificar la existencia de variables / valores profundamente anidados sin tener que verificar cada variable en el camino ...

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

Ex. - una matriz de objetos profundamente anidada:

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

En lugar de :

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

Ahora podemos:

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

¡Salud!


fuente
1
Si la solución es usar eval, acaba de crear un millón de otros problemas.
Rodrigo Leite
@RodrigoLeite bien, por lo que no sería un problema para dar al menos una ...
1
@RodrigoLeite Lo he leído y actualizado la solución para usar Functionen su lugar
0

Hice una pregunta que se duplicó un poco sobre este tema hace un tiempo, y después de una investigación excesiva, y viendo que falta mucha información que debería estar aquí, siento que tengo algo valioso que agregar a esta publicación anterior.

  • En primer lugar, quiero abordar que hay varias formas de obtener el valor de una propiedad y almacenarla en una variable dinámica. La primera forma más popular y más fácil en mi humilde opinión sería:
let properyValue = element.style['enter-a-property'];

sin embargo, rara vez tomo esta ruta porque no funciona en valores de propiedad asignados a través de hojas de estilo. Para darle un ejemplo, lo demostraré con un poco de pseudocódigo.

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

Usando el ejemplo de código anterior; si la propiedad de ancho del elemento div que se almacenó en la variable 'elem' se diseñó en una hoja de estilo CSS, y no se diseñó dentro de su etiqueta HTML, sin duda obtendrá un valor de retorno de indefinido almacenado en el interior de la variable cssProp. El valor indefinido ocurre porque para obtener el valor correcto, el código escrito dentro de una hoja de estilo CSS debe calcularse para obtener el valor, por lo tanto; debe usar un método que calcule el valor de la propiedad cuyo valor se encuentra dentro de la hoja de estilo.

  • ¡De ahora en adelante el método getComputedStyle ()!
function getCssProp(){
  let ele = document.getElementById("test");
  let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}

W3Schools getComputedValue Doc Esto proporciona un buen ejemplo y le permite jugar con él, sin embargo, este enlace Mozilla CSS getComputedValue doc habla sobre la función getComputedValue en detalle, y debe ser leído por cualquier desarrollador aspirante que no esté totalmente claro sobre este tema.

  • Como nota al margen, el método getComputedValue solo obtiene, no se establece. Esto, obviamente, es una desventaja importante, sin embargo, hay un método que se obtiene de las hojas de estilo CSS, así como también establece valores, aunque no es Javascript estándar. El método JQuery ...
$(selector).css(property,value)

... consigue y establece. Es lo que uso, el único inconveniente es que debes conocer JQuery, pero esta es honestamente una de las muchas buenas razones por las que todo desarrollador de Javascript debería aprender JQuery, simplemente hace la vida más fácil y ofrece métodos, como este, que no está disponible con Javascript estándar. ¡¡¡Espero que esto ayude a alguien!!!

Aft3rL1f3
fuente
0

Para cualquiera que busque establecer el valor de una variable anidada, aquí se explica cómo hacerlo:

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

Documentación: https://lodash.com/docs/4.17.15#set

Además, documentación si desea obtener un valor: https://lodash.com/docs/4.17.15#get

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

something[\`${foo}\`];
Sergey
fuente
77
¿Por qué razón harías tú eso? Tu fooya es una cadena, por lo que `${foo}`es exactamente lo mismo que foo. (Además, el código parece tener algunas barras invertidas adicionales que no pertenecen allí Pero aún sería inútil incluso si se fija que error de sintaxis..)
Ilmari Karonen