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.