Javascript usa variável como nome de objeto

89

Quero usar o valor de uma variável para acessar um objeto.

Digamos que eu tenha um objeto chamado myobject.

Quero preencher uma variável com este nome e usar a variável para acessar o objeto.

Exemplo:

var objname = 'myobject';
{objname}.value = 'value';
PeeHaa
fonte

Respostas:

123

Global:

myObject = { value: 0 };
anObjectName = "myObject";
this[anObjectName].value++;

console.log(this[anObjectName]);

Global: v2

var anObjectName = "myObject";
this[anObjectName] = "myvalue"

console.log(myObject)

Local: v1

(function() {
    var scope = this;

    if (scope != arguments.callee) {
        arguments.callee.call(arguments.callee);
        return false;
    }

    scope.myObject = { value: 0 };
    scope.anObjectName = "myObject";
    scope[scope.anObjectName].value++;

    console.log(scope.myObject.value);
})();

Local: v2

(function() {  
    var scope = this;

    scope.myObject = { value: 0 };
    scope.anObjectName = "myObject";
    scope[scope.anObjectName].value++;

    console.log(scope.myObject.value);    
}).call({});
Shaz
fonte
@Shaz - ambos fazem referência ao mesmo escopo ;-) (presumindo que sejam executados em um navegador) alert(this === window).
Sean Vieira
1
@PeeHaa - O local exemplo define uma variável no windowobjeto chamado objnameque é então referenciado via this... você pode substituir windowpor thisno segundo exemplo e tudo iria funcionar ainda. :-)
Sean Vieira
1
@SeanVieira: Dê uma olhada no exemplo atualizado. Espero que isso funcione corretamente agora.
Shaz de
1
@Shaz - arguments.calleeestá obsoleto, mas é uma implementação muito inteligente, no entanto - e não desorganiza o escopo global. +1
Sean Vieira
1
Pode não estar poluindo o escopo global, mas está criando um objeto que é compartilhado por cada invocação da função. Sua função é mantida objnamecomo uma propriedade da própria função. Ele pode falhar para funções recursivas. Não tenho certeza de como isso pode ser usado no mundo real.
Juan Mendes
25

Use colchetes ao redor do nome da variável.

var objname = 'myobject';
{[objname]}.value = 'value';
Vaishali Venkatesan
fonte
6
Isso é perfeito e simples e deve ser a resposta principal.
Brad
4
Isso lança uma exceção: SyntaxError: expressão esperada, obtido '.'. Não funciona; por que tantos votos positivos?
Lovro
8

É uma variável global? Nesse caso, eles são realmente parte do windowobjeto, então você pode fazer window[objname].value.

Se for local para uma função, não acho que haja uma boa maneira de fazer o que você deseja.

JW.
fonte
7

O objeto existe em algum escopo, então você quase sempre pode acessar a variável por meio desta sintaxe:

var objname = "myobject";
containing_scope_reference[objname].some_property = 'some value';

O único lugar onde isso fica complicado é quando você está em um escopo fechado e deseja acessar uma variável local de nível superior. Quando você tem algo assim:

(function(){
    var some_variable = {value: 25};
    var x = "some_variable";
    console.log(this[x], window[x]); // Doesn't work
})();

Você pode contornar isso usando evalpara acessar a cadeia de escopo atual ... mas não recomendo, a menos que você tenha feito muitos testes e saiba que essa é a melhor maneira de fazer as coisas.

(function(){
    var some_variable = {value: 25};
    var x = "some_variable";
    eval(x).value = 42;
    console.log(some_variable); // Works
})();

Sua melhor aposta é ter uma referência a um nome em um objeto que sempre estará lá (como thisno escopo global ou uma variável de nível superior privada em um escopo local) e colocar todo o resto lá.

Portanto:

var my_outer_variable = {};
var outer_pointer = 'my_outer_variable';
// Reach my_outer_variable with this[outer_pointer]
// or window[outer_pointer]

(function(){
    var my_inner_scope = {'my_inner_variable': {} };
    var inner_pointer = 'my_inner_variable';
    // Reach my_inner_variable by using
    // my_inner_scope[inner_pointer]
})();
Sean Vieira
fonte
6

Você pode usar eval:

eval(variablename + ".value = 'value'");
Midas
fonte
Não é evalconsiderado evil? Se não, posso usá-lo. Porque é global agora, mas eu queria movê-lo para uma função para limpar as coisas.
PeeHaa
1
Ri muito. Se o nome da variável vier da entrada do usuário, certifique-se de validá-lo, para que não contenha nenhum código JS que evalpossa ser executado.
Midas de
1
Este é um dos poucos usos legítimos de eval, em minha opinião. No entanto, precisamos ter certeza de que a variável está limpa.
Levi Morrison
2
Sim, não é realmente um problema. Mas dê uma olhada na resposta de Shaz. Acho que é uma solução mais limpa.
Midas de
2
@PeeHaa: Se você está pensando em movê-lo, por que não movê-lo para uma propriedade de um objeto conhecido, para que possa fazer algo como myVar[objname].value?
JW.
5

Você não pode fazer isso em geral, exceto no escopo da janela, onde você pode escrever window[objname].value = 'value';

Neil
fonte
3

Acho que a resposta de Shaz para variáveis ​​locais é difícil de entender, embora funcione para funções não recursivas. Aqui está outra maneira que eu acho mais clara (mas ainda é ideia dele, exatamente o mesmo comportamento). Ele também não está acessando as variáveis ​​locais dinamicamente, apenas a propriedade da variável local.

Basicamente, ele está usando uma variável global (anexada ao objeto de função)

// Here's  a version of it that is more straight forward.
function doIt() {
    doIt.objname = {};
    var someObject = "objname";
    doIt[someObject].value = "value";    
    console.log(doIt.objname);
})();

O que é essencialmente a mesma coisa que criar um global para armazenar a variável, para que você possa acessá-la como uma propriedade. Criar um global para fazer isso é um hack.

Aqui está um hack mais limpo que não cria variáveis ​​globais; em vez disso, ele usa uma variável local.

function doIt() {
  var scope = {
     MyProp: "Hello"
  };
  var name = "MyProp";
  console.log(scope[name]);
}

Veja Javascript: interpretar string como referência de objeto?

Juan Mendes
fonte
0

Ao usar a janela [objname], certifique-se de que o objname são variáveis ​​globais. Caso contrário, funcionará em algum momento e falhará às vezes. janela [objname] .value.

lyon819
fonte
0

Se o objeto estiver em algum namespace, por exemplo. Company.Module.Components.Foovocê pode usar esta função:

CoffeeScript:

objByName: (name, context = window) ->
    ns = name.split "."
    func = context
    for n, i in ns
        func = func[n]
    return func

Js resultantes:

objByName: function(name, context) {
  var func, i, n, ns, _i, _len;
  if (context == null) {
    context = window;
  }
  ns = name.split(".");
  func = context;
  for (i = _i = 0, _len = ns.length; _i < _len; i = ++_i) {
    n = ns[i];
    func = func[n];
  }
  return func;
}

Então você pode criar um novo objeto ou fazer o que for. Observe os parênteses.

var o = new (objByName('Company.Module.Components.Foo'))
objByName('some.deeply.nested.object').value

Esta ideia é emprestada de uma questão semelhante: Como executar uma função JavaScript quando tenho seu nome como uma string

Comunidade
fonte
0

Um dos desafios que tive com as respostas é que presumia que o objeto era um único nível. Por exemplo,

const testObj = { testKey: 'testValue' }
const refString = 'testKey';
const refObj = testObj[refString];

funciona bem, mas

const testObj = { testKey:
                  { level2Key: 'level2Value' }
                }
const refString = 'testKey.level2Key';
const refObj = testObj[refString];

não funciona.

O que acabei fazendo foi construir uma função para acessar objetos multinível:

objVar(str) {
    let obj = this;
    const parts = str.split('.');
    for (let p of parts) {
        obj = obj[p];
    }
    return obj;
}

No segundo cenário, então, posso passar a string para esta função para recuperar o objeto que estou procurando:

const testObj = { testKey:
                  { level2Key: 'level2Value' }
                }
const refString = 'testObj.testKey.level2Key';
const refObj = objVar[refString];
Mitch Parker
fonte
0

Você pode definir uma propriedade de objetos desta forma:

var obj = {};
obj.whateverVarName = 'yourVal';
console.log(obj);

ThisisFish
fonte
0

Se você já conhece a lista de nomes de variáveis ​​possíveis, tente criar um novo objeto (iconObj) cujos nomes de propriedades sejam iguais aos nomes de objetos. Aqui no exemplo abaixo, a variável iconLib conterá dois valores de string, 'ZondIcons' ou 'MaterialIcons' . propertyName é propriedade do objeto ZondIcons ou MaterialsIcon.

   const iconObj = {
    ZondIcons,
    MaterialIcons,
  }
  const objValue = iconObj[iconLib][propertyName]
verão
fonte
0
let players = [];
players[something] = {};
players[something].somethingElse = 'test';
console.log(players); 

-> [algo: {algoElse: 'teste'}];

part1cle
fonte
-1
var micro=[{'test':'hello'}];

var device = 'test';

console.log(micro[device]);
alfonsoolavarria
fonte