Acessar dinamicamente a propriedade do objeto usando a variável


Respostas:


959

Existem duas maneiras de acessar propriedades de um objeto:

  • Notação de ponto: something.bar
  • Notação de suporte: something['bar']

O valor entre colchetes pode ser qualquer expressão. Portanto, se o nome da propriedade estiver armazenado em uma variável, você precisará usar a notação de colchete:

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

34
cuidado com isso: compiladores javascript será erro aqui desde que não cordas renomear mas eles propriedades do objeto renomear
— chacham15

6
Mais algumas informações sobre por que isso é possível: objetos JS são matrizes associativas, é por isso. Leitura adicional: quirksmode.org/js/associative.html stackoverflow.com/questions/14031368/…
— Sudhanshu Mishra

@dotnetguy Não, eles não são. Matrizes são objetos que herdam do protótipo de objeto JS simples e, portanto, você pode adicionar propriedades como um objeto simples. O comportamento 'associativo' é mais parecido com um objeto do que com uma matriz. Você não pode iterar a versão 'associativa' por um índice simples, para que ela não exiba comportamento semelhante a um array. Você pode definir sua matriz 'associativa' como {} ou [] e tratá-la da mesma forma em ambos os casos, no que diz respeito ao acesso aleatório à propriedade.
— Vanquished Wombat

3
@VanquishedWombat Não sabe ao certo qual é a sua objeção? Eu não disse que objetos JS são matrizes?
— Sudhanshu Mishra

1
Esta resposta é super-votada, não esclarece nada ...
— Aft3rL1f3 17/01

104

Esta é a minha solução:

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

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

Resposta excelente, veja também: stackoverflow.com/questions/37510640/…
— Julian Knight

2
Você me inspirou a criar uma versão melhorada, que permite suporte de notação e de propriedade nomes com espaços bem como validar as entradas: it.knightnet.org.uk/kb/node-js/get-properties
— Julian Knight

Eu amo essa solução. No entanto, estou tentando modificar os valores no objeto original, parece que sua função retorna uma sub-cópia do objeto. É possível alterá-lo para que a modificação do objeto retornado modifique o original?
— eagle1

40

Em javascript, podemos acessar com:

  • notação de ponto - foo.bar
  • colchetes - foo[someVar]oufoo["string"]

Mas apenas o segundo caso permite acessar propriedades dinamicamente:

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
Estou olhando para 2.000 linhas de instruções if porque o desenvolvedor anterior não usou colchetes e propriedades de objetos acessadas estaticamente por notação de ponto. É para um aplicativo de processo de aprovação que possui 7 aprovadores diferentes e as etapas são iguais. / rip
— Chade

26

A seguir, é apresentado um exemplo do ES6 de como você pode acessar a propriedade de um objeto usando um nome de propriedade que foi gerado dinamicamente pela concatenação de duas cadeias.

var suffix = " name";

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

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

Isso é chamado de nomes de propriedades computados


16

Você pode conseguir isso de várias maneiras diferentes.

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

foo.bar;
foo['bar'];

A notação de colchete é especialmente poderosa, pois permite acessar uma propriedade com base em uma variável:

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

let prop = 'bar';

foo[prop];

Isso pode ser estendido ao loop sobre todas as propriedades de um objeto. Isso pode parecer redundante devido a construções JavaScript mais recentes, como para ... de ..., mas ajuda a ilustrar um 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]);
}

A notação de ponto e colchete também funciona conforme o esperado para objetos aninhados:

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

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

Destruição de objetos

Também podemos considerar a destruição de objetos como um meio de acessar uma propriedade em um objeto, mas da seguinte maneira:

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

Você pode fazer isso usando o Lodash get

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

Existem muitas situações, como pesquisas profundas de objetos aninhados, em que essa é a única opção.
— Jonathan Kempf

8

ATUALIZADA

Levei em consideração os comentários abaixo e concordei. Eval deve ser evitado.

O acesso às propriedades raiz no objeto é facilmente alcançado obj[variable], mas ficar aninhado complica as coisas. Para não escrever código já escrito, sugiro usar lodash.get.

Exemplo

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

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

O Lodash get pode ser usado de diferentes maneiras. Aqui está o link para a documentação lodash.get


4
É melhor evitar usar evalsempre que possível. stackoverflow.com/questions/86513/…
— Luke

8
Usar evalalgo tão trivial quanto acessar propriedades é um exagero e dificilmente aconselhável sob nenhuma circunstância. O que é "problema"? obj['nested']['test']funciona muito bem e não requer que você incorpore código em strings.
— Kyll

3
eval é três vezes mais lento ou mais, eu não recomendaria isso aos iniciantes, porque isso poderia ensinar-lhes maus hábitos. Eu uso obj['nested']['value']- lembre-se crianças, eval é mau!
— jaggedsoft

1
@ Lucas Ele agora é o único que quer trazer Lodash _.getpara a mesa. Penso que esta resposta merece agora votos em vez de votos negativos. Pode ser um exagero, mas é bom saber que existe.
— Emile Bergeron

1
Obrigado por apresentar o lodash para isso. Eu vim aqui pelo google procurando um método para definir um valor profundo em um objeto e usei o método _.set (que é idêntico ao acima, mas com a argumentação extra para o valor a ser definido).
— Tbughes

5

Sempre que você precisar acessar a propriedade dinamicamente, precisará usar colchetes para acessar a propriedade, não "." operador
Sintaxe: 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

Me deparei com um caso em que achava que queria passar o "endereço" de uma propriedade de objeto como dados para outra função e preencher o objeto (com AJAX), pesquisar na matriz de endereços e exibir nessa outra função. Eu não poderia usar a notação de ponto sem fazer acrobacias de string, então pensei que uma matriz poderia ser boa para passar. Acabei fazendo algo diferente de qualquer maneira, mas parecia relacionado a este post.

Aqui está uma amostra de um objeto de arquivo de idioma como o de onde eu queria dados:

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

Eu queria poder transmitir uma matriz como: ["audioPlayer", "controls", "stop"] para acessar o texto do idioma, "stop" neste caso.

Eu criei essa pequena função que consulta o parâmetro de endereço "menos específico" (primeiro) e reatribui o objeto retornado a si mesmo. Então, está pronto para procurar o próximo parâmetro de endereço mais específico, se houver algum.

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

2

Fica interessante quando você também precisa passar parâmetros para essa função.

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

1

ES5 // Verificar variáveis ​​profundamente aninhadas

Este simples trecho de código pode verificar a existência de variáveis ​​/ valores profundamente aninhados sem precisar verificar cada variável ao longo do caminho ...

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

Ex. - uma matriz de objetos profundamente aninhada:

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

Ao invés 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

Agora podemos:

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

Felicidades!


1
Se a solução é usar eval, você acabou de criar um milhão de outros problemas.
— Rodrigo Leite

@RodrigoLeite ok, por isso não seria um problema para dar pelo menos um ...


1
@RodrigoLeite Eu li e atualizei a solução para usar em Functionvez disso

0

Eu fiz uma pergunta que meio que foi duplicada sobre esse tópico há algum tempo, e após uma pesquisa excessiva e vendo muitas informações ausentes que deveriam estar aqui, sinto que tenho algo valioso a acrescentar a este post antigo.

  • Em primeiro lugar, quero abordar que existem várias maneiras de obter o valor de uma propriedade e armazená-lo em uma variável dinâmica. A primeira maneira mais popular e mais fácil de IMHO seria:
let properyValue = element.style['enter-a-property'];

no entanto, raramente vou nessa rota porque não funciona nos valores de propriedades atribuídos por meio de folhas de estilo. Para dar um exemplo, demonstrarei com um pouco de pseudo-código.

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

Usando o exemplo de código acima; se a propriedade width do elemento div que foi armazenada na variável 'elem' foi estilizada em uma folha de estilo CSS e não estilizada dentro de sua tag HTML, sem dúvida você obterá um valor de retorno de indefinido armazenado dentro da variável cssProp. O valor indefinido ocorre porque, para obter o valor correto, o código escrito em uma folha de estilo CSS precisa ser calculado para obter o valor; você deve usar um método que calcule o valor da propriedade cujo valor esteja na folha de estilos.

  • A partir de agora o método getComputedStyle ()!
function getCssProp(){
  let ele = document.getElementById("test");
  let cssProp = window.getComputedStyle(ele,null).getPropertyValue("width");
}

W3Schools getComputedValue Doc Isso fornece um bom exemplo e permite que você brinque com ele, no entanto, este link O documento getComputedValue do CSS do Mozilla fala sobre a função getComputedValue em detalhes e deve ser lido por qualquer desenvolvedor que não seja totalmente claro sobre esse assunto.

  • Como observação lateral, o método getComputedValue apenas obtém, não é definido. Isso, obviamente, é uma grande desvantagem, no entanto, existe um método que obtém das folhas de estilo CSS, além de definir valores, embora não seja Javascript padrão. O método JQuery ...
$(selector).css(property,value)

... recebe e define. É o que eu uso, a única desvantagem é que você conhece o JQuery, mas essa é honestamente uma das muitas boas razões para que todo desenvolvedor Javascript deva aprender o JQuery, isso facilita a vida e oferece métodos como este, que não está disponível com Javascript padrão. Espero que isso ajude alguém !!!




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

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

7
Por que diabos você faria isso? Você foojá é uma string, então `${foo}`é exatamente o mesmo que foo. (Além disso, o código parece ter algumas barras invertidas extras que não pertencem lá Mas ainda seria inútil mesmo se você fixa que erro de sintaxe..)
— Ilmari Karonen
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.