Usa nomi di variabili dinamiche in JavaScript


344

In PHP puoi fare cose incredibili / orrende come questa:

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

Esiste un modo per fare qualcosa del genere con Javascript?

Ad esempio, se ho un var name = 'the name of the variable';posso ottenere un riferimento alla variabile con nome name?


2
Possibile duplicato di stackoverflow.com/questions/724857/… e stackoverflow.com/questions/1664282/… , ma la risposta accettata qui è migliore, IMO.
addio

Questo risponde alla tua domanda? Variabili "variabili" in Javascript? . La risposta accettata è migliore di quella qui perché mostra come farlo, ma avverte anche correttamente che c'è quasi sempre un modo migliore per fare qualunque cosa tu voglia fare . Vedi il problema XY su meta.
Ggorlen,

Risposte:


354

Dal momento che ECMA- / Javascript è tutto Objectse Contexts(che sono anche un po 'oggetto), ogni variabile è memorizzata in una tale variabile (o nel caso di una funzione, oggetto di attivazione ).

Quindi se crei variabili come questa:

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

Nell'ambito globale (= NO contesto della funzione), si scrivono implicitamente quelle variabili nell'oggetto globale (= windowin un browser).

È possibile accedervi utilizzando la notazione "punto" o "parentesi":

var name = window.a;

o

var name = window['a'];

Questo funziona solo per l'oggetto globale in questo caso particolare, perché l' oggetto variabile del oggetto globale è l' windowoggetto stesso. Nel contesto di una funzione, non si ha accesso diretto all'oggetto Activation . Per esempio:

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 nuova istanza di un oggetto auto-definito (contesto). Senza newl'ambito della funzione sarebbe anche global(= finestra). Questo esempio avviserebbe undefinede 1rispettivamente. Se sostituiremo this.a = 1; this.b = 2con:

var a = 1,
    b = 2;

Entrambe le uscite di allarme sarebbero indefinite. In quello scenario, le variabili ae bverrebbero archiviate nell'oggetto Activation da foobarcui non possiamo accedere (ovviamente potremmo accedervi direttamente chiamando ae b).


1
Un'altra cosa interessante è che in questo modo è possibile aggiungere la richiamata (inizio / fine) per qualsiasi funzione di livello globale.
antitossico

5
Ma cosa succede se la mia variabile dinamica è locale in una funzione? ad esempio: funzione boink () {var a = 1; // questo non funzionerà var dynamic = this ['a']; // anche questo non funzionerà var dynamic = ['a']; }
Kokodoko,

@ Kokodoko — perché questo non è un "contesto" o un riferimento al contesto di esecuzione di una funzione (non c'è modo di fare riferimento a un contesto di esecuzione, è proibito dall'ECMA-262). questo è impostato da come viene chiamata (o da un bind ) una funzione , è solo un oggetto che non ha nulla a che fare con il contesto di esecuzione in cui è accessibile.
RobG,

Se è necessario accedere alle proprietà nidificate, consultare stackoverflow.com/questions/4244896/…
Mr Br,

mi ha indicato nella giusta direzione con la notazione parentesi. Era bloccato pensando solo alla notazione a punti.
Andrew

149

eval è un'opzione.

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

document.write(eval(name)); // 1

19
No, non dovrebbe esserlo dato che eval è malvagio. Non usare mai eval!
EasyBB,

52
@EasyBB - se hai intenzione di dire di non usare mai qualcosa, non sono utile per spiegare il perché. Ho una situazione in cui non riesco a pensare a nessun altro modo di realizzare ciò che sto facendo oltre a eval ()
Rampant Creative Group

4
Eval rappresenta un rischio di attacchi agli utenti finali e non saremo tecnicamente malvagi piuttosto fraintesi e abusati in una perdita di casi. Ho visto le risposte php che contengono letteralmente vari e poi usano eval per eseguirlo. Anche se questo non dovrebbe essere usato in questo caso in quanto esistono metodi migliori. Questa domanda a portata di mano eval non dovrebbe essere utilizzata affatto poiché ci sono metodi migliori nel complesso e sono sicuro che molti di noi lo sanno.
EasyBB

2
Tramite javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval --- "Consideriamo gli argomenti più frequentemente confrontati con l'utilizzo di eval: 1) Richiede una compilazione ed è quindi lento 2) Cosa succede se un script malevoli si sono fatti strada nell'argomento eval? 3) Sembra brutto 4) Eredita il contesto di esecuzione e questo vincolo dell'ambito in cui è invocato "
mattLummus

1
Ecco come creare variabili dinamiche usando eval: stackoverflow.com/a/13291766/5528600
am2124429

80

È possibile utilizzare l'oggetto finestra per accedervi.

window['myVar']

window ha un riferimento a tutte le variabili globali e alle funzioni globali che stai utilizzando.


28
E inutile dirlo, questo è più sicuro di eval ().
Cray,

45

Solo non so quale cattiva risposta ottenga così tanti voti. È una risposta abbastanza semplice ma la rendi complessa.

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

13
"in una funzione che usiamo this" - Se si desidera accedere a una variabile globale in questo modo, è meglio essere espliciti e usare l' windowoggetto, non this. thisè ambiguo.
MrWhite,

1
Ma all'interno di una funzione non puoi usare this, o altro, per accedere alla variabile typedal tuo esempio, se hai il suo nome in un'altra variabile: function test(vname) { var type = 'article'; this[vname] = 'something else'; alert(type); }; test('type')mostrerà article, no something else. E questo è ciò che spiega la "risposta complessa".
Orafu

28
a = 'varname';
str = a+' = '+'123';
eval(str)
alert(varname);

Prova questo...


27

Questo è un esempio:

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

Un altro esempio :

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

alert(coco); // display : riko

Quindi, il valore " coco " di myVariable diventa un coco variabile .

Perché tutte le variabili nell'ambito globale sono proprietà dell'oggetto Window.


14

In Javascript puoi usare il fatto che tutte le proprietà sono coppie chiave-valore. jAndy lo ha già menzionato ma non credo che la sua risposta mostri come possa essere sfruttata.

Di solito non si sta tentando di creare una variabile per contenere un nome di variabile, ma si sta provando a generare nomi di variabili e quindi utilizzarli. PHP lo fa con $$varnotazione ma Javascript non è necessario perché le chiavi delle proprietà sono intercambiabili con le chiavi dell'array.

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

dà 123. Di solito vuoi costruire la variabile ed è per questo che c'è il riferimento indiretto così puoi farlo anche al contrario.

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

1
var someJsonObj = {}; in un ciclo .... for (var i = 0; i <= 3; i ++) {someJsonObj [i] = []; }, ma posso essere qualsiasi cosa. variabili così generate dinamicamente, siedono tutte all'interno di someJsonObj per un facile riferimento.
rajeev,

5

2019

TL; DR

  • eval l'operatore può eseguire l'espressione di stringa nel contesto chiamato e restituire variabili da quel contesto;
  • literal objectteoricamente può farlo scrivendo:, {[varName]}ma è bloccato per definizione.

Quindi mi imbatto in questa domanda e tutti qui giocano solo senza portare una soluzione reale. ma @Axel Heider ha un buon approccio.

La soluzione è eval. operatore quasi dimenticato. (pensa che la maggior parte sia with())

evall'operatore può eseguire in modo dinamico espressione nel contesto chiamato. e restituisce il risultato di quell'espressione. possiamo usarlo per restituire dinamicamente il valore di una variabile nel contesto della funzione.

esempio:

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

Nota che scrivo sempre esplicitamente che evalverrà eseguita l'espressione . Per evitare inutili sorprese nel codice. evalè molto forte Ma sono sicuro che lo sai già

A proposito, se fosse legale potremmo usare literal objectper acquisire il nome e il valore della variabile, ma non possiamo combinare nomi di proprietà calcolati e abbreviazione del valore della proprietà, purtroppo, non è valido

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

    var capture = {[varName]}

}

example('var1') //trow 'Uncaught SyntaxError: Unexpected token }`

È una soluzione rapida, ma è una cattiva pratica perché non è sicura e riduce le prestazioni poiché il motore JS non è in grado di ottimizzare quel metodo.
Diego Ortiz,

Ottima soluzione
Rohit Parte

4

Se non vuoi usare un oggetto globale come window o global (nodo), puoi provare qualcosa del genere:

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

console.log(obj['whatever']);

4

Avevo bisogno di disegnare più FormData al volo e l'oggetto funzionava bene

var forms = {}

Quindi nei miei loop dove avevo bisogno di creare un modulo di dati che ho usato

forms["formdata"+counter]=new FormData();
forms["formdata"+counter].append(var_name, var_value);

Grazie ... Mi ha totalmente salvato! questo. $ refs ['listView' + index] .nativeView.animate ({..}) Avevo bisogno di vari all'interno di refs come questo. $ refs.listView1 listView2 e così via ...
Meiki Neumann

2

Questa è un'alternativa per coloro che devono esportare una variabile con nome dinamico

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

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

Un'altra alternativa è semplicemente creare un oggetto le cui chiavi sono denominate in modo dinamico

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

// consume it like this
vars[someVariable];

1

quello che vogliono dire è no, non puoi. non c'è modo di farlo. quindi era possibile che tu potessi fare qualcosa del genere

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

}

avere una funzione di creazione proprio come quella implementata in ECMAScript 5.


4
Attenzione: const è una parola chiave in ES6
Tejas Manohar,

4
... e prima era una parola riservata per il futuro .
TJ Crowder,

c'è evaloperatore
pery mimon

1

eval () non ha funzionato nei miei test. Ma è possibile aggiungere un nuovo codice JavaScript all'albero DOM. Quindi ecco una funzione che aggiunge una nuova variabile:

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)

2
piccolo miglioramento, è meglio usare var node_head = document.getElementsByTagName("head")[0]al posto di ID, come nessuno dà id="head"per <head>:-)
ddlab

Lo faccio :) Ma grazie, ora posso finalmente rimuovere questa cosa `id =" testa "
Axel Heider,

1
Questo sembra essere un modo troppo complesso di creare una variabile globale ?! (... e come risponde alla domanda?)
MrWhite,

genio :) eval è la soluzione. Anche se il tuo codice non funziona
pery mimon

1

Sebbene questa abbia una risposta accettata, vorrei aggiungere un'osservazione:

In ES6 l'utilizzo let non funziona :

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

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

Comunque usando var funziona

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

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

Spero che questo possa essere utile ad alcuni.


1
lo stesso vale perconst

1
Vero. Ma è possibile creare un oggetto con le variabili e selezionare la variabile da lì: const vars = { t, m, b }; console.log(vars['b']). Altrimenti evalfunziona anche.
Fabian von Ellerts,

0

anche l'oggetto è fantastico.

var a=123
var b=234
var temp = {"a":a,"b":b}
console.log(temp["a"],temp["b"]);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.