Use nomes de variáveis ​​dinâmicas em JavaScript

344

No PHP, você pode fazer coisas incríveis / horrendas como esta:

$a = 1;
$b = 2;
$c = 3;
$name = 'a';
echo $$name;
// prints 1

Existe alguma maneira de fazer algo assim com Javascript?

Por exemplo, se eu tiver um, var name = 'the name of the variable';posso obter uma referência à variável com nome name?

Finbarr
fonte
2
Possível fraude de stackoverflow.com/questions/724857/… e stackoverflow.com/questions/1664282/… , mas a resposta aceita aqui melhor, IMO.
Goodeye
Isso responde sua pergunta? Variáveis ​​"variáveis" em Javascript? . A resposta aceita é melhor do que a aqui, porque mostra como fazê-lo, mas também adverte corretamente que quase sempre há uma maneira melhor de fazer o que você deseja fazer . Veja o problema XY na meta.
ggorlen

Respostas:

353

Como o ECMA- / Javascript tem tudo a ver Objectse Contexts(que também é um tipo de objeto), todas as variáveis ​​são armazenadas em uma variável chamada variável- (ou no caso de uma função, objeto de ativação ).

Portanto, se você criar variáveis ​​como esta:

var a = 1,
    b = 2,
    c = 3;

No escopo Global (= NO contexto da função), você escreve implicitamente essas variáveis ​​no objeto Global (= windowem um navegador).

Esses podem ser acessados ​​usando a notação "ponto" ou "colchete":

var name = window.a;

ou

var name = window['a'];

Isso só funciona para o objeto global, neste caso particular, porque o objeto variável do objeto global é o windowobjeto em si. Dentro do contexto de uma função, você não tem acesso direto ao objeto de ativação . Por exemplo:

function foobar() {
   this.a = 1;
   this.b = 2;

   var name = window['a']; // === undefined
   alert(name);
   name = this['a']; // === 1
   alert(name);
}

new foobar();

newcria uma nova instância de um objeto auto-definido (contexto). Sem newo escopo da função seria também global(= window). Este exemplo alertaria undefinede 1respectivamente. Se substituirmos this.a = 1; this.b = 2por:

var a = 1,
    b = 2;

Ambas as saídas de alerta seriam indefinidas. Nesse cenário, as variáveis ae bseriam armazenadas no objeto de ativação a partir do foobarqual não podemos acessar (é claro que poderíamos acessá-las diretamente chamando ae b).

jAndy
fonte
11
Outra coisa interessante é que dessa maneira você pode adicionar retorno de chamada (início / fim) para qualquer função de nível global.
Antitóxico
5
Mas e se minha variável dinâmica for local em uma função? por exemplo: função boink () {var a = 1; // isso não funcionará var dynamic = this ['a']; // isso também não funcionará var dynamic = ['a']; }
Kokodoko 28/10
@ Kokodoko - porque este não é "contexto" ou uma referência ao contexto de execução de uma função (não há como referenciar um contexto de execução, é proibido pelo ECMA-262). Isso é definido pela maneira como uma função é chamada (ou por bind ), é apenas um Objeto que não tem nada a ver com o contexto de execução em que é acessível.
RobG
Se você precisar acessar propriedades aninhadas, consulte stackoverflow.com/questions/4244896/…
Sr. Br
me apontou na direção certa com a notação de colchete. Estava preso pensando apenas em notação de ponto.
Andrew Andrew
149

eval é uma opção.

var a = 1;
var name = 'a';

document.write(eval(name)); // 1
erickb
fonte
19
Não, não deveria ser tão mau quanto avaliar. Nunca use eval!
EasyBB 18/01
52
@ EasyBB - se você vai dizer para nunca usar algo, não é útil explicar o porquê. Eu tenho uma situação em que eu não consigo pensar em qualquer outra maneira de conseguir o que estou fazendo diferente de eval ()
desenfreado Creative Group
4
O Eval representa um risco de ataques a usuários finais e não será tecnicamente ruim, mas mal compreendido e mal utilizado em casos perdidos. Eu vi respostas php que contêm vars literais nele e usam eval para executá-lo. Embora isso não deva ser usado neste caso, pois existem métodos melhores. Esta questão em avaliação não deve ser usada, pois existem métodos melhores em geral e tenho certeza que muitos de nós sabemos disso.
EasyBB 25/03
2
Via javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval --- "Vamos considerar os argumentos mais frequentemente nivelados contra o uso de eval: 1) Requer uma compilação e, portanto, é lento 2) E se um ? script malicioso encontrou seu caminho para o argumento eval 3) parece feio 4) Ele herda o contexto de execução e esta ligação do escopo em que a sua invocado"
mattLummus
11
Aqui está como criar variáveis ​​dinâmicas usando eval: stackoverflow.com/a/13291766/5528600
am2124429
80

Você pode usar o objeto window para acessá-lo.

window['myVar']

window tem uma referência a todas as variáveis ​​globais e funções globais que você está usando.

JohnP
fonte
28
E escusado será dizer que este é mais seguro que eval ().
Cray
45

Só não sei o que uma resposta ruim recebe tantos votos. É uma resposta bastante fácil, mas você a torna complexa.

// If you want to get article_count
// var article_count = 1000;
var type = 'article';
this[type+'_count'] = 1000;  // in a function we use "this";
alert(article_count);
Terry Lin
fonte
13
"em uma função que usamos this" - Se você deseja acessar uma variável global dessa maneira, é melhor ser explícito e usar o windowobjeto, não this. thisé ambíguo.
precisa saber é o seguinte
11
Mas dentro de uma função você não pode usar this, ou qualquer outra coisa, para acessar a variável typedo seu exemplo, se você tiver o nome em outra variável: function test(vname) { var type = 'article'; this[vname] = 'something else'; alert(type); }; test('type')será exibido article, não something else. E é isso que a "resposta complexa" explica.
Orafu 6/01
28
a = 'varname';
str = a+' = '+'123';
eval(str)
alert(varname);

Tente isso ...

amável
fonte
27

Isto é um exemplo :

for(var i=0; i<=3; i++) {
    window['p'+i] = "hello " + i;
}

alert(p0); // hello 0
alert(p1); // hello 1
alert(p2); // hello 2
alert(p3); // hello 3

Outro exemplo :

var myVariable = 'coco';
window[myVariable] = 'riko';

alert(coco); // display : riko

Portanto, o valor " coco " de myVariable se torna um coco variável .

Porque todas as variáveis ​​no escopo global são propriedades do objeto Window.

Azódio
fonte
14

Em Javascript, você pode usar o fato de que todas as propriedades são pares de valores-chave. jAndy já mencionou isso, mas não acho que a resposta dele mostre como pode ser explorada.

Normalmente você não está tentando criar uma variável para armazenar um nome de variável, mas está tentando gerar nomes de variáveis ​​e depois usá-los. O PHP faz isso com $$varnotação, mas o Javascript não precisa, porque as chaves de propriedade são intercambiáveis ​​com as chaves da matriz.

var id = "abc";
var mine = {};
mine[id] = 123;
console.log(mine.abc);

dá 123. Geralmente você deseja construir a variável e é por isso que existe a indireção, para que você também possa fazer o contrário.

var mine = {};
mine.abc = 123;
console.log(mine["a"+"bc"]);
David Newcomb
fonte
11
var someJsonObj = {}; em um loop .... for (var i = 0; i <= 3; i ++) {someJsonObj [i] = []; }, mas eu posso ser qualquer coisa. Assim, variáveis ​​geradas dinamicamente, todas ficam dentro de someJsonObj para facilitar a referência.
rajeev
5

2019

TL; DR

  • eval O operador pode executar a expressão de seqüência de caracteres no contexto chamado e retornar variáveis ​​desse contexto;
  • literal objectteoricamente, podemos fazer isso escrevendo:, {[varName]}mas bloqueado por definição.

Então, me deparei com essa pergunta e todos aqui brincam sem trazer uma solução real. mas @Axel Heider tem uma boa abordagem.

A solução é eval. operador quase mais esquecido. (pense mais um with())

evalO operador pode executar dinamicamente a expressão no contexto que chamou. e retorne o resultado dessa expressão. podemos usar isso para retornar dinamicamente o valor de uma variável no contexto da função.

exemplo:

function exmaple1(){
   var a = 1, b = 2, default = 3;
   var name = 'a';
   return eval(name)
}

example1() // return 1


function example2(option){
  var a = 1, b = 2, defaultValue = 3;

  switch(option){
    case 'a': name = 'a'; break;
    case 'b': name = 'b'; break;
    default: name = 'defaultValue';
  }
  return eval (name);
}

example2('a') // return 1
example2('b') // return 2
example2() // return 3

Observe que eu sempre escrevo explicitamente que a expressão evalserá executada. Para evitar surpresas desnecessárias no código. evalé muito forte, mas tenho certeza que você já sabe disso

BTW, se fosse legal, poderíamos usar literal objectpara capturar o nome e o valor da variável, mas não podemos combinar nomes de propriedades computados e valores abreviados de propriedades, infelizmente, são inválidos.

functopn example( varName ){
    var var1 = 'foo', var2 ='bar'

    var capture = {[varName]}

}

example('var1') //trow 'Uncaught SyntaxError: Unexpected token }`
pery mimon
fonte
É uma solução rápida, mas é uma prática ruim porque não é segura e diminui o desempenho, pois o mecanismo JS não pode otimizar esse método.
Diego Ortiz
Solução impressionante
Rohit Parte
4

Se você não quiser usar um objeto global como window ou global (node), tente algo como isto:

var obj = {};
obj['whatever'] = 'There\'s no need to store even more stuff in a global object.';

console.log(obj['whatever']);
Brent Barbata
fonte
4

Eu precisava desenhar vários FormData em tempo real e o objeto funcionou bem

var forms = {}

Em seguida, nos meus loops, sempre que necessário, para criar os dados do formulário que usei

forms["formdata"+counter]=new FormData();
forms["formdata"+counter].append(var_name, var_value);
Talha
fonte
Obrigado ... Isso me salvou totalmente! this. $ refs ['listView' + index] .nativeView.animate ({..}) Eu precisava de vários dentro de refs como este. $ refs.listView1 listView2 e assim por diante ...
Meiki Neumann
2

Essa é uma alternativa para quem precisa exportar uma variável nomeada dinamicamente

export {
  [someVariable]: 'some value',
  [anotherVariable]: 'another value',
}

// then.... import from another file like this:
import * as vars from './some-file'

Outra alternativa é simplesmente criar um objeto cujas chaves sejam nomeadas dinamicamente

const vars = { [someVariable]: 1, [otherVariable]: 2 };

// consume it like this
vars[someVariable];
JeanAlesi
fonte
1

o que eles querem dizer é não, você não pode. não há como fazê-lo. então era possível que você pudesse fazer algo assim

function create(obj, const){
// where obj is an object and const is a variable name
function const () {}

const.prototype.myProperty = property_value;
// .. more prototype

return new const();

}

tendo uma função de criação como a implementada no ECMAScript 5.

Alfgaar
fonte
4
Cuidado: const é uma palavra-chave no ES6
Tejas Manohar
4
... e antes disso era uma palavra reservada no futuro .
TJ Crowder
existe evaloperador
pery mimon
1

eval () não funcionou nos meus testes. Mas é possível adicionar um novo código JavaScript à árvore do DOM. Então, aqui está uma função que adiciona uma nova variável:

function createVariable(varName,varContent)
{
  var scriptStr = "var "+varName+"= \""+varContent+"\""

  var node_scriptCode = document.createTextNode( scriptStr )
  var node_script = document.createElement("script");
  node_script.type = "text/javascript"
  node_script.appendChild(node_scriptCode);

  var node_head = document.getElementsByTagName("head")[0]
  node_head.appendChild(node_script);
}

createVariable("dynamicVar", "some content")
console.log(dynamicVar)
Axel Heider
fonte
2
pequena melhora, é melhor usar var node_head = document.getElementsByTagName("head")[0]em vez de ID, como ninguém dá uma id="head"para <head>:-)
ddlab
Eu faço :) Mas obrigado, agora eu posso finalmente remover este `id = "cabeça" coisa
Axel Heider
11
Isso parece ser uma maneira muito complexa de criar uma variável global ?! (... e como é que esta resposta à pergunta?)
MrWhite
gênio :) eval é a solução. Mesmo que o seu código não funciona
pery mimon
1

Embora isso tenha uma resposta aceita, gostaria de acrescentar uma observação:

No ES6, o uso let não funciona :

/*this is NOT working*/
let t = "skyBlue",
    m = "gold",
    b = "tomato";

let color = window["b"];
console.log(color);

No entanto, usando var obras

/*this IS working*/
var t = "skyBlue",
    m = "gold",
    b = "tomato";

let color = window["b"];
console.log(color);

Espero que isso possa ser útil para alguns.

enxaneta
fonte
11
o mesmo se aplica aconst
11
Verdade. Mas você pode criar um objeto com as variáveis e selecione a variável de lá: const vars = { t, m, b }; console.log(vars['b']). Caso contrário, evaltambém funciona.
Fabian von Ellerts
0

use Object também é ótimo.

var a=123
var b=234
var temp = {"a":a,"b":b}
console.log(temp["a"],temp["b"]);
Steve Jiang
fonte