Utiliser des noms de variables dynamiques en JavaScript

344

En PHP, vous pouvez faire des choses incroyables / horribles comme ceci:

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

Existe-t-il un moyen de faire quelque chose comme ça avec Javascript?

Par exemple, si j'ai un, var name = 'the name of the variable';puis-je obtenir une référence à la variable avec un nom name?

Finbarr
la source
2
Dupe possible de stackoverflow.com/questions/724857/… et stackoverflow.com/questions/1664282/… , mais la réponse acceptée ici est meilleure, IMO.
revoir
Est-ce que cela répond à votre question? Des variables "variables" en Javascript? . La réponse acceptée là-bas est meilleure que celle ici car elle montre comment le faire, mais avertit également correctement qu'il y a presque toujours une meilleure façon de faire tout ce que vous voulez faire . Voir le problème XY sur la méta.
ggorlen

Réponses:

353

Puisque ECMA- / Javascript est tout au sujet de Objectset Contexts(qui sont également une sorte d'objet), chaque variable est stockée dans une telle appelée Variable- (ou dans le cas d'une fonction, un objet d'activation ).

Donc, si vous créez des variables comme ceci:

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

Dans la portée globale (= contexte de fonction NO), vous écrivez implicitement ces variables dans l' objet global (= windowdans un navigateur).

Ceux-ci sont accessibles en utilisant la notation "point" ou "parenthèse":

var name = window.a;

ou

var name = window['a'];

Cela ne fonctionne que pour l'objet global dans cette instance particulière, car l' objet variable de l' objet global est l' windowobjet lui-même. Dans le contexte d'une fonction, vous n'avez pas d'accès direct à l' objet d'activation . Par exemple:

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

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

new foobar();

newcrée une nouvelle instance d'un objet auto-défini (contexte). Sans newla portée de la fonction serait également global(= fenêtre). Cet exemple alerterait undefinedet 1respectivement. Si nous remplacions this.a = 1; this.b = 2par:

var a = 1,
    b = 2;

Les deux sorties d'alerte ne seraient pas définies. Dans ce scénario, les variables aet bseraient stockées dans l'objet d'activation à partir foobarduquel nous ne pouvons pas accéder (bien sûr, nous pourrions accéder directement à celles-ci en appelanta et b).

jAndy
la source
1
Une autre chose intéressante est que de cette façon, vous pouvez ajouter un rappel (début / fin) pour n'importe quelle fonction de niveau global.
antitoxique
5
Mais que faire si ma variable dynamique est locale dans une fonction? par exemple: fonction boink () {var a = 1; // cela ne fonctionnera pas var dynamic = this ['a']; // cela ne fonctionnera pas non plus var dynamic = ['a']; }
Kokodoko
@ Kokodoko - parce que ce n'est pas un "contexte" ou une référence au contexte d'exécution d'une fonction (il n'y a aucun moyen de référencer un contexte d'exécution, c'est interdit par l'ECMA-262). cela est défini par la façon dont une fonction est appelée (ou par liaison ), c'est juste un objet qui n'a rien à voir avec le contexte d'exécution dans lequel elle est accessible.
RobG
Si vous avez besoin d'accéder à des propriétés imbriquées, consultez stackoverflow.com/questions/4244896/…
Mr Br
m'a pointé dans la bonne direction avec la notation crochet. A été bloqué en pensant uniquement à la notation par points.
Andrew
149

eval est une option.

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

document.write(eval(name)); // 1
erickb
la source
19
Non, cela ne devrait pas, car l'eval est mauvais. N'utilisez jamais eval!
EasyBB
52
@EasyBB - si vous allez dire de ne jamais utiliser quelque chose, je ne peux pas expliquer pourquoi. J'ai une situation dans laquelle je ne peux penser à aucune autre façon d'accomplir ce que je fais à part eval ()
Rampant Creative Group
4
Eval présente un risque d'attaques contre les utilisateurs finaux et nous ne serons pas techniquement mal plutôt mal compris et mal utilisés dans une perte de cas. J'ai vu des réponses php qui contiennent des variables littérales, puis utilisent eval pour l'exécuter. Bien que cela ne doive pas être utilisé dans ce cas car il existe de meilleures méthodes. Cette question à portée de main ne devrait pas du tout être utilisée car il existe de meilleures méthodes dans l'ensemble et je suis sûr que beaucoup d'entre nous le savent.
EasyBB
2
Via javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval --- "Considérons les arguments les plus fréquemment opposés à l'utilisation d'eval: 1) Il nécessite une compilation et est donc lent 2) Et si un un script malveillant a trouvé son chemin dans l'argument eval? 3) Il a l'air moche 4) Il hérite du contexte d'exécution et de cette liaison de la portée dans laquelle il est invoqué "
mattLummus
1
Voici comment créer des variables dynamiques en utilisant eval: stackoverflow.com/a/13291766/5528600
am2124429
80

Vous pouvez utiliser l'objet fenêtre pour y accéder.

window['myVar']

window contient une référence à toutes les variables globales et fonctions globales que vous utilisez.

JohnP
la source
28
Et il va sans dire que celui-ci est plus sûr que eval ().
Cray
45

Je ne sais pas ce qu'une mauvaise réponse obtient autant de votes. C'est une réponse assez simple mais vous la rendez complexe.

// 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
la source
13
"dans une fonction que nous utilisons this" - Si vous voulez accéder à une variable globale de cette façon, il vaut mieux être explicite et utiliser l' windowobjet, non this. thisc'est ambigu.
MrWhite
1
Mais à l' intérieur d'une fonction, vous ne pouvez pas utiliser this, ou quoi que ce soit d'autre, pour accéder à la variable typede votre exemple, si vous avez son nom dans une autre variable: function test(vname) { var type = 'article'; this[vname] = 'something else'; alert(type); }; test('type')s'affichera article, non something else. Et c'est ce qu'explique la «réponse complexe».
Orafu
28
a = 'varname';
str = a+' = '+'123';
eval(str)
alert(varname);

Essaye ça...

amitchd
la source
27

Ceci est un exemple :

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 autre exemple :

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

alert(coco); // display : riko

Ainsi, la valeur " coco " de myVariable devient un coco variable .

Parce que toutes les variables de la portée globale sont des propriétés de l'objet Window.

Azodium
la source
14

En Javascript, vous pouvez utiliser le fait que toutes les propriétés sont des paires clé-valeur. jAndy l'a déjà mentionné, mais je ne pense pas que sa réponse montre comment cela peut être exploité.

Habituellement, vous n'essayez pas de créer une variable pour contenir un nom de variable, mais essayez de générer des noms de variable, puis de les utiliser. PHP le fait avec $$varnotation mais Javascript n'est pas nécessaire car les clés de propriété sont interchangeables avec les clés de tableau.

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

donne 123. Habituellement, vous voulez construire la variable, c'est pourquoi il y a l'indirection afin que vous puissiez également le faire dans l'autre sens.

var mine = {};
mine.abc = 123;
console.log(mine["a"+"bc"]);
David Newcomb
la source
1
var someJsonObj = {}; dans une boucle .... pour (var i = 0; i <= 3; i ++) {someJsonObj [i] = []; }, mais je peux être n'importe quoi. donc des variables générées dynamiquement, toutes se trouvent à l'intérieur de someJsonObj pour une référence facile.
rajeev
5

2019

TL; DR

  • eval L'opérateur peut exécuter l'expression de chaîne dans le contexte qu'il a appelé et renvoyer des variables de ce contexte;
  • literal objectpeut théoriquement le faire en écrivant:, {[varName]}mais il a bloqué par définition.

Je tombe donc sur cette question et tout le monde ici joue juste sans apporter une vraie solution. mais @Axel Heider a une bonne approche.

La solution est eval. opérateur presque le plus oublié. (pense que la plupart sontwith() )

evalL'opérateur peut exécuter dynamiquement l'expression dans le contexte qu'il a appelé. et retourner le résultat de cette expression. nous pouvons l'utiliser pour retourner dynamiquement la valeur d'une variable dans le contexte de la fonction.

exemple:

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

Notez que j'écris toujours explicitement l'expression evals'exécutera. Pour éviter des surprises inutiles dans le code. evalest très fort Mais je suis sûr que vous savez que déjà

BTW, si c'était légal, nous pourrions utiliser literal objectpour capturer le nom et la valeur de la variable, mais nous ne pouvons pas combiner les noms de propriété calculés et la valeur de la propriété, malheureusement, n'est pas valide

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

    var capture = {[varName]}

}

example('var1') //trow 'Uncaught SyntaxError: Unexpected token }`
pery mimon
la source
C'est une solution rapide, mais c'est une mauvaise pratique car elle n'est pas sûre et diminue les performances car le moteur JS ne peut pas optimiser cette méthode.
Diego Ortiz
Solution
géniale
4

Si vous ne souhaitez pas utiliser un objet global comme window ou global (node), vous pouvez essayer quelque chose comme ceci:

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

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

Je devais dessiner plusieurs FormData à la volée et la méthode d'objet fonctionnait bien

var forms = {}

Ensuite, dans mes boucles où j'avais besoin de créer un formulaire de données que j'utilisais

forms["formdata"+counter]=new FormData();
forms["formdata"+counter].append(var_name, var_value);
Talha
la source
Merci ... Cela m'a totalement sauvé! $ refs ['listView' + index] .nativeView.animate ({..}) J'avais besoin de vars à l'intérieur de refs comme ceci. $ refs.listView1 listView2 et ainsi de suite ...
Meiki Neumann
2

Ceci est une alternative pour ceux qui ont besoin d'exporter une variable nommée dynamiquement

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

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

Une autre alternative consiste à créer simplement un objet dont les clés sont nommées dynamiquement

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

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

ce qu'ils signifient est non, vous ne pouvez pas. il n'y a aucun moyen de le faire. il était donc possible que vous puissiez faire quelque chose comme ça

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

}

ayant une fonction de création comme celle implémentée dans ECMAScript 5.

Alfgaar
la source
4
Attention: const est un mot-clé dans ES6
Tejas Manohar
4
... et avant cela était un futur mot réservé .
TJ Crowder
il y a un evalopérateur
pery mimon
1

eval () n'a pas fonctionné dans mes tests. Mais l'ajout de nouveau code JavaScript à l'arborescence DOM est possible. Voici donc une fonction qui ajoute une nouvelle 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
la source
2
petite amélioration, il vaut mieux utiliser à la var node_head = document.getElementsByTagName("head")[0]place de l'ID, car personne ne donne un id="head"à <head>:-)
ddlab
Je le fais :) Mais merci, maintenant je peux enfin supprimer cette chose `id =" head "
Axel Heider
1
Cela semble juste être une manière trop complexe de créer une variable globale?! (... et comment cela répond-il à la question?)
MrWhite
genius :) eval est la solution. Même si votre code ne fonctionne pas
Pery Mimon
1

Bien que cela ait une réponse acceptée, je voudrais ajouter une observation:

Dans ES6, l'utilisation let ne fonctionne pas :

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

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

Cependant en utilisant des var œuvres

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

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

J'espère que cela pourra être utile à certains.

enxaneta
la source
1
il en va de même pourconst
1
Vrai. Mais vous pouvez créer un objet avec les variables et sélectionnez la variable à partir de là: const vars = { t, m, b }; console.log(vars['b']). Sinon, ça evalmarche aussi.
Fabian von Ellerts du
0

utiliser Object est super aussi.

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