Búsqueda de sitios web

javascript - Accediendo a una propiedad de un objeto con un nombre calculado dinámicamente


Estoy intentando acceder a una propiedad de un objeto usando un nombre dinámico. ¿Es esto posible?

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

Respuesta #1

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

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

El valor entre los corchetes puede ser cualquier expresión. Por lo tanto, si el nombre de la propiedad se almacena en una variable, tienes que usar la notación de corchetes:

var something = {
  bar: 'foo'
};
var foo = 'bar';

// both x = something[foo] and something[foo] = x work as expected
console.log(something[foo]);
console.log(something.bar)

Respuesta #2

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

Respuesta #3

En JavaScript podemos acceder con:

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

Pero solo el segundo caso permite acceder a las propiedades de manera dinámica:

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

Respuesta #4

A continuación se muestra un ejemplo en ES6 de cómo se puede acceder a la propiedad de un objeto utilizando un nombre de propiedad que ha sido generado dinámicamente concatenando 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 computadas

Respuesta #5

Puedes lograr esto de varias maneras diferentes.

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

foo.bar;
foo['bar'];

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

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

let prop = 'bar';

foo[prop];

Esto se puede extender a recorrer cada propiedad de un objeto. Esto puede parecer redundante debido a constructos más recientes de JavaScript como for ... of ..., 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]);
}

Tanto la notación de punto como la de corchetes también funcionan como se espera para 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'

Respuesta #6

Puedes hacerlo así usando Lodash get

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

Respuesta #7

actualizada

Acceder a las propiedades raíz en un objeto se logra fácilmente con obj[variable], pero obtener propiedades anidadas complica las cosas. Para no escribir código ya escrito, 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, la documentación lodash.get

Respuesta #8

Para acceder a una propiedad de manera dinámica, simplemente usa corchetes [] de la siguiente manera:

const something = { bar: "Foobar!" };
const userInput = 'bar';
console.log(something[userInput])

El problema

¡Hay un gran inconveniente en esa solución! (Me sorprende que otras respuestas no lo hayan mencionado todavía). A menudo solo quieres acceder a las propiedades que tú mismo has puesto en ese objeto, no quieres tomar propiedades heredadas.

Aquí hay una ilustración de este problema. Aquí tenemos un programa que parece inocente, pero tiene un error sutil: ¿puedes detectarlo?

const agesOfUsers = { sam: 16, sally: 22 }
const username = prompt('Enter a username:')
if (agesOfUsers[username] !== undefined) {
  console.log(`${username} is ${agesOfUsers[username]} years old`)
} else {
  console.log(`${username} is not found`)
}

Cuando se te pida un nombre de usuario, si proporcionas "toString" como nombre de usuario, te dará el siguiente mensaje: "toString es function toString() { [código nativo] } años de edad". El problema es que agesOfUsers es un objeto y, como tal, hereda automáticamente ciertas propiedades como .toString() de la clase base Object. Puedes mirar aquí una lista completa de propiedades que todos los objetos heredan.

Soluciones

  1. Usa en su lugar una estructura de datos Map. El contenido almacenado de un mapa no sufre problemas de prototipo, por lo que proporciona una solución limpia a este problema.

const agesOfUsers = new Map()
agesOfUsers.set('sam', 16)
agesOfUsers.set('sally', 2)
console.log(agesOfUsers.get('sam')) // 16

  
  1. Utiliza un objeto con un prototipo nulo, en lugar del prototipo por defecto. Puedes usar Object.create(null) para crear dicho objeto. Este tipo de objeto no sufre de estos problemas de prototipo, porque lo has creado explícitamente de una manera que no hereda nada.

const agesOfUsers = Object.create(null)
agesOfUsers.sam = 16
agesOfUsers.sally = 22;
console.log(agesOfUsers['sam']) // 16
console.log(agesOfUsers['toString']) // undefined - toString was not inherited

  
  1. Puedes usar Object.hasOwn(yourObj, attrName) para primero verificar si la clave dinámica que deseas acceder está directamente en el objeto y no es heredada (aprende más aquí). Esta es una característica relativamente nueva, así que revisa las tablas de compatibilidad antes de incluirla en tu código. Antes de que existiera Object.hasOwn(yourObj, attrName), lograbas el mismo efecto usando Object.prototype.hasOwnProperty.call(yourObj, attrName). A veces, podrías ver código usando yourObj.hasOwnProperty(attrName) también, lo cual a veces funciona, pero tiene algunas desventajas sobre las que puedes leer aquí.

// Try entering the property name "toString",
// you'll see it gets handled correctly.
const user = { name: 'sam', age: 16 }
const propName = prompt('Enter a property name:')
if (Object.hasOwn(user, propName)) {
  console.log(`${propName} = ${user[propName]}`)
} else {
  console.log(`${propName} is not found`)
}
  1. Si sabes que la clave que estás intentando usar nunca será el nombre de una propiedad heredada (por ejemplo, tal vez sean números, o todos tengan el mismo prefijo, etc.), puedes optar por usar la solución original.

Artículos relacionados