Use nombres de variables dinámicas en JavaScript

344

En PHP puedes hacer cosas increíbles / horrendas como esta:

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

¿Hay alguna forma de hacer algo así con Javascript?

Por ejemplo, si tengo una, var name = 'the name of the variable';¿puedo obtener una referencia a la variable con nombre name?

Finbarr
fuente
2
Posible engaño de stackoverflow.com/questions/724857/… , y stackoverflow.com/questions/1664282/… , pero la respuesta aceptada aquí es mejor, IMO.
goodeye
¿Responde esto a tu pregunta? ¿Variables "variables" en Javascript? . La respuesta aceptada allí es mejor que la de aquí porque muestra cómo hacerlo, pero también advierte correctamente que casi siempre hay una mejor manera de hacer lo que sea que quieras hacer . Ver problema XY en meta.
ggorlen

Respuestas:

353

Dado que ECMA- / Javascript se trata Objectsy Contexts(que también son una especie de Objeto), cada variable se almacena en una variable llamada Variable- (o en el caso de una Función, Objeto de Activación ).

Entonces, si creas variables como esta:

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

En el ámbito Global (= contexto de función NO), usted escribe implícitamente esas variables en el objeto Global (= windowen un navegador).

Se puede acceder a ellos utilizando la notación "punto" o "paréntesis":

var name = window.a;

o

var name = window['a'];

Esto sólo funciona para el objeto global en este caso particular, debido a que el objeto variable del objeto global es el windowobjeto en sí. Dentro del contexto de una función, no tiene acceso directo al objeto de activación . Por ejemplo:

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

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

new foobar();

newcrea una nueva instancia de un objeto autodefinido (contexto). Sin newel alcance de la función también sería global(= ventana). Este ejemplo alertaría undefinedy 1respectivamente. Si reemplazáramos this.a = 1; this.b = 2con:

var a = 1,
    b = 2;

Ambas salidas de alerta estarían indefinidas. En ese escenario, las variables ay bse almacenarían en el Objeto de Activación desde el foobarcual no podemos acceder (por supuesto, podríamos acceder a ellas directamente llamando ay b).

jAndy
fuente
1
Otra cosa interesante es que de esta manera puede agregar devolución de llamada (inicio / fin) para cualquier función de nivel global.
antitóxico el
55
Pero, ¿qué pasa si mi variable dinámica es local en una función? por ejemplo: function boink () {var a = 1; // esto no funcionará var dynamic = this ['a']; // esto tampoco funcionará var dynamic = ['a']; }
Kokodoko
@ Kokodoko: porque esto no es "contexto" o una referencia al contexto de ejecución de una función (no hay forma de hacer referencia a un contexto de ejecución, está prohibido por el ECMA-262). esto se establece por cómo se llama una función (o por enlace ), es solo un Objeto que no tiene nada que ver con el contexto de ejecución en el que es accesible.
RobG
Si necesita acceder a propiedades anidadas, consulte stackoverflow.com/questions/4244896/…
Mr Br
me señaló en la dirección correcta con la notación de corchetes. Estaba atascado pensando solo en la notación de puntos.
Andrew
149

eval Es una opción.

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

document.write(eval(name)); // 1
erickb
fuente
19
No, no debería, ya que eval es malvado. ¡Nunca use eval!
EasyBB
52
@EasyBB: si vas a decir que nunca uses algo, no soy útil para explicar por qué. Tengo una situación en la que no puedo pensar en otra forma de lograr lo que estoy haciendo que no sea eval ()
Rampant Creative Group
44
Eval plantea un riesgo de ataques a los usuarios finales y consideramos que no es técnicamente malvado sino más bien mal entendido y mal utilizado en una pérdida de casos. He visto respuestas php que contienen vars literales y luego usan eval para ejecutarlo. Aunque esto no debería usarse en este caso, ya que hay mejores métodos. Esta pregunta en mano eval no debe usarse en absoluto, ya que existen mejores métodos en general y estoy seguro de que muchos de nosotros lo sabemos.
EasyBB
2
A través de javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval --- "Consideremos los argumentos más frecuentes contra el uso de eval: 1) Requiere una compilación y, por lo tanto, es lento 2) ¿Qué pasa si un script malicioso encontrado en el argumento eval? 3) Parece feo 4) Hereda el contexto de ejecución y este enlace del alcance en el que se invoca "
mattLummus
1
Aquí se explica cómo crear variables dinámicas con eval: stackoverflow.com/a/13291766/5528600
am2124429
80

Puede usar el objeto de ventana para llegar a él.

window['myVar']

window tiene una referencia a todas las variables globales y funciones globales que está utilizando.

JohnP
fuente
28
Y no hace falta decir que este es más seguro que eval ().
Cray
45

Simplemente no sé qué mala respuesta obtiene tantos votos. Es una respuesta bastante fácil, pero la haces compleja.

// 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
fuente
13
"en una función que usamos this": si desea acceder a una variable global de esta manera, es mejor ser explícito y usar el windowobjeto, no this. thises ambiguo.
MrWhite
1
Pero dentro de una función que no puede usar this, o cualquier otra cosa, para acceder a la variable typedesde su ejemplo, si tiene su nombre en otra variable: function test(vname) { var type = 'article'; this[vname] = 'something else'; alert(type); }; test('type')se mostrará article, no something else. Y eso es lo que explica la "respuesta compleja".
Orafu
28
a = 'varname';
str = a+' = '+'123';
eval(str)
alert(varname);

Prueba esto...

amitchd
fuente
27

Esto es un ejemplo :

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

Otro ejemplo :

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

alert(coco); // display : riko

Entonces, el valor " coco " de myVariable se convierte en un coco variable .

Porque todas las variables en el ámbito global son propiedades del objeto Window.

Azodio
fuente
14

En Javascript puede usar el hecho de que todas las propiedades son pares de valores clave. jAndy ya mencionó esto, pero no creo que su respuesta muestre cómo se puede explotar.

Por lo general, no está intentando crear una variable para contener un nombre de variable, sino que está tratando de generar nombres de variables y luego usarlos. PHP lo hace con $$varnotación, pero Javascript no lo necesita porque las claves de propiedad son intercambiables con las claves de matriz.

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

da 123. Por lo general, desea construir la variable, razón por la cual existe la indirección, por lo que también puede hacerlo al revés.

var mine = {};
mine.abc = 123;
console.log(mine["a"+"bc"]);
David Newcomb
fuente
1
var someJsonObj = {}; en un bucle .... for (var i = 0; i <= 3; i ++) {someJsonObj [i] = []; }, pero puedo ser cualquier cosa. Por lo tanto, las variables generadas dinámicamente se ubican dentro de someJsonObj para facilitar la referencia.
rajeev
5

2019

TL; DR

  • eval el operador puede ejecutar una expresión de cadena en el contexto que llamó y devolver variables de ese contexto;
  • literal objectteóricamente puede hacerlo escribiendo: {[varName]}pero bloqueado por definición.

Así que me encuentro con esta pregunta y todos aquí solo juegan sin aportar una solución real. pero @Axel Heider se acerca bien.

La solución es eval. operador casi olvidado. (creo que la mayoría es with())

evalEl operador puede ejecutar dinámicamente la expresión en el contexto al que llamó. y devuelve el resultado de esa expresión. podemos usar eso para devolver dinámicamente el valor de una variable en el contexto de la función.

ejemplo:

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

Tenga en cuenta que siempre escribo explícitamente la expresión evalse ejecutará. Para evitar sorpresas innecesarias en el código. evales muy fuerte pero estoy seguro de que ya lo sabes

Por cierto, si fuera legal, podríamos usar literal objectpara capturar el nombre y el valor de la variable, pero no podemos combinar los nombres de propiedad calculados y el valor de la propiedad, por desgracia, no es válido

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

    var capture = {[varName]}

}

example('var1') //trow 'Uncaught SyntaxError: Unexpected token }`
pery mimon
fuente
Es una solución rápida, pero es una mala práctica porque no es segura y disminuye el rendimiento ya que el motor JS no puede optimizar ese método.
Diego Ortiz
Solución impresionante
Rohit Parte
4

Si no desea utilizar un objeto global como window o global (nodo), puede intentar algo como esto:

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

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

Necesitaba dibujar múltiples FormData sobre la marcha y la forma de objeto funcionó bien

var forms = {}

Luego, en mis bucles, donde sea que necesitaba crear un formulario de datos que utilicé

forms["formdata"+counter]=new FormData();
forms["formdata"+counter].append(var_name, var_value);
Talha
fuente
Gracias ... ¡Me salvó totalmente! this. $ refs ['listView' + index] .nativeView.animate ({..}) Necesitaba vars dentro de referencias como esta. $ refs.listView1 listView2 y así sucesivamente ...
Meiki Neumann
2

Esta es una alternativa para aquellos que necesitan exportar una variable con nombre dinámico

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

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

Otra alternativa es simplemente crear un objeto cuyas claves se denominen dinámicamente

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

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

lo que quieren decir es no, no puedes. No hay forma de hacerlo. así que era posible que pudieras hacer algo como esto

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

}

tener una función de creación como la implementada en ECMAScript 5.

Alfgaar
fuente
44
Cuidado: const es una palabra clave en ES6
Tejas Manohar
44
... y antes de eso era una palabra reservada en el futuro .
TJ Crowder
hay evaloperador
pery mimon
1

eval () no funcionó en mis pruebas. Pero es posible agregar un nuevo código JavaScript al árbol DOM. Entonces, aquí hay una función que agrega una nueva variable:

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
fuente
2
pequeña mejora, es mejor usar en var node_head = document.getElementsByTagName("head")[0]lugar de ID, ya que nadie le da id="head"a <head>:-)
ddlab
Sí :) Pero gracias, ahora finalmente puedo eliminar esta cosa `id =" head "
Axel Heider
1
¡¿Esto parece ser una forma demasiado compleja de crear una variable global ?! (... y ¿cómo responde esto a la pregunta?)
MrWhite
genio :) eval es la solución. Incluso si su código no funciona
pery mimon
1

Aunque esto tiene una respuesta aceptada, me gustaría agregar una observación:

En ES6, el uso let no funciona :

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

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

Sin embargo usando var trabajos

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

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

Espero que esto pueda ser útil para algunos.

enxaneta
fuente
1
lo mismo se aplica aconst
1
Cierto. Sin embargo, puede crear un objeto con las variables y seleccione la variable a partir de ahí: const vars = { t, m, b }; console.log(vars['b']). De lo contrario evaltambién funciona.
Fabian von Ellerts
0

use Object también es genial.

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