Используйте имена динамических переменных в JavaScript


344

В PHP вы можете делать удивительные / ужасные вещи, как это:

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

Есть ли способ сделать что-то подобное с Javascript?

Например, если у меня есть, var name = 'the name of the variable';я могу получить ссылку на переменную с именем name?


2
Возможно дублирование stackoverflow.com/questions/724857/… и stackoverflow.com/questions/1664282/… , но принятый здесь ответ лучше, IMO.
Goodeye

Отвечает ли это на ваш вопрос? «Переменные» переменные в Javascript? , Принятый ответ там лучше, чем здесь, потому что он показывает, как это сделать, но также правильно предупреждает, что почти всегда есть лучший способ сделать то, что вы хотите сделать . Смотрите проблему XY на мета.
ggorlen

Ответы:


354

Поскольку ECMA- / Javascript - это все Objectsи Contexts(которые также являются некими объектами), каждая переменная хранится в так называемой переменной (или в случае функции, объекта активации). ).

Так что если вы создаете переменные, как это:

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

В глобальной области видимости (= НЕТ контекста функции) вы неявно записываете эти переменные в глобальный объект (= windowв браузере).

К ним можно получить доступ, используя обозначение «точка» или «скобка»:

var name = window.a;

или

var name = window['a'];

Это работает только для глобального объекта в данном конкретном случае, так как переменная объекта из глобального объекта является windowсамим объектом. В контексте функции у вас нет прямого доступа к объекту активации . Например:

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

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

new foobar();

newсоздает новый экземпляр самоопределяемого объекта (контекста). Без newобъема функции также будет global(= окно). Этот пример предупредит undefinedи 1соответственно. Если бы мы заменили this.a = 1; this.b = 2на:

var a = 1,
    b = 2;

Оба выхода оповещения будут неопределенными. В этом сценарии переменные aи bбудут храниться в объекте активации, из foobarкоторого мы не можем получить доступ (конечно, мы можем получить доступ к ним напрямую, вызвав aи b).


1
Еще одна интересная вещь: таким образом вы можете добавить функцию обратного вызова (начало / конец) для любой функции глобального уровня.
антитоксическое

5
Но что, если моя динамическая переменная является локальной в функции? например: функция boink () {var a = 1; // это не сработает var dynamic = this ['a']; // это также не сработает var dynamic = ['a']; }
Kokodoko

@ Kokodoko - потому что это не «контекст» или ссылка на контекст выполнения функции (нет способа ссылаться на контекст выполнения, это запрещено ECMA-262). это определяется способом вызова функции (или связыванием ), это просто объект, который не имеет ничего общего с контекстом выполнения, в котором она доступна.
RobG

Если вам нужен доступ к вложенным свойствам, ознакомьтесь со stackoverflow.com/questions/4244896/…
г-н Бр

указал мне в правильном направлении с примечанием скобки. Застрял, думая только о точечных обозначениях.
Андрей

149

eval это один из вариантов.

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

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

19
Нет, это не должно быть, поскольку eval - зло. Никогда не используйте eval!
EasyBB

52
@EasyBB - если вы собираетесь сказать, что никогда не используете что-то, я не помогу объяснить, почему У меня есть ситуация, в которой я не могу придумать какой-либо другой способ выполнить то, что я делаю, кроме eval ()
Rampant Creative Group

4
Eval представляет риск для атак на конечных пользователей, и мы будем считать, что это не технически зло, а неправильно понято и неправильно использовано в потерянных случаях. Я видел ответы php, которые содержат буквенные переменные, а затем используют eval для его запуска. Хотя это не должно использоваться в этом случае, поскольку есть лучшие методы. Этот вопрос под рукой eval не должен использоваться вообще, так как в целом есть лучшие методы, и я уверен, что многие из нас знают это.
EasyBB

2
Через javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval --- «Давайте рассмотрим аргументы, наиболее часто выровненные против использования eval: 1) он требует компиляции и поэтому медленен 2) что если Вредоносный сценарий нашел свой путь в аргументе eval? 3) Он выглядит уродливо 4) Он наследует контекст выполнения и это связывание с областью, в которой его вызывали "
mattLummus

1
Вот как создать динамические переменные с помощью eval: stackoverflow.com/a/13291766/5528600
am2124429

80

Вы можете использовать объект окна, чтобы добраться до него.

window['myVar']

window имеет ссылку на все глобальные переменные и глобальные функции, которые вы используете.


28
И, разумеется, этот безопаснее, чем eval ().
Cray

45

Просто не знаю, какой плохой ответ набирает столько голосов. Это довольно простой ответ, но вы делаете его сложным.

// 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
«в функции, которую мы используем this» - если вы хотите получить доступ к глобальной переменной таким способом, лучше быть явным и использовать windowобъект, а не this. thisнеоднозначно.
MrWhite

1
Но внутри функции, которую вы не можете использовать thisили что-либо еще, для доступа к переменной typeиз вашего примера, если у вас есть имя в другой переменной: function test(vname) { var type = 'article'; this[vname] = 'something else'; alert(type); }; test('type')покажет article, а не something else. И это то, что объясняет «сложный ответ».
Орафу


27

Это пример:

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

Другой пример :

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

alert(coco); // display : riko

Таким образом, значение « кокос » myVariable становится переменной кокос .

Потому что все переменные в глобальной области видимости являются свойствами объекта Window.


14

В Javascript вы можете использовать тот факт, что все свойства являются парами ключ-значение. Энди уже упоминал об этом, но я не думаю, что его ответ показывает, как его можно использовать.

Обычно вы не пытаетесь создать переменную для хранения имени переменной, но пытаетесь сгенерировать имена переменных и затем использовать их. PHP делает это с помощью $$varнотации, но Javascript не нужен, потому что ключи свойств взаимозаменяемы с ключами массива.

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

дает 123. Обычно вы хотите построить переменную, поэтому существует косвенное направление, поэтому вы можете сделать это и наоборот.

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

1
var someJsonObj = {}; в цикле .... for (var i = 0; i <= 3; i ++) {someJsonObj [i] = []; }, но я могу быть чем угодно. динамически генерируемые переменные, все они находятся внутри someJsonObj для удобства.
Раджив

5

2019

TL; DR

  • eval оператор может запустить строковое выражение в контексте, который он вызвал, и вернуть переменные из этого контекста;
  • literal objectТеоретически это можно сделать с помощью write:, {[varName]}но оно заблокировано по определению.

Поэтому я сталкиваюсь с этим вопросом, и все здесь просто играют, не предлагая реального решения. но у @Axel Heider хороший подход.

Решение есть eval. почти самый забытый оператор. (думаю, что большинство из них with())

evalОператор может динамически запускать выражение в контексте, который он вызвал. и вернуть результат этого выражения. мы можем использовать это, чтобы динамически возвращать значение переменной в контексте функции.

пример:

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

Обратите внимание, что я всегда пишу явно, выражение evalбудет выполняться. Чтобы избежать ненужных сюрпризов в коде. evalочень сильный, но я уверен, что вы уже знаете, что

Кстати, если бы это было законно, мы могли бы использовать literal objectдля захвата имени и значения переменной, но мы не можем объединить сокращенные имена и значение свойства, к сожалению, недопустимо

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

    var capture = {[varName]}

}

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

Это быстрое решение, но это плохая практика, потому что это небезопасно и снижает производительность, поскольку движок JS не может оптимизировать этот метод.
Диего Ортис

Отличное решение
Rohit Parte

4

Если вы не хотите использовать глобальный объект, такой как окно или глобальный (узел), вы можете попробовать что-то вроде этого:

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

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

4

Мне нужно было нарисовать несколько FormData на лету, и способ объекта работал хорошо

var forms = {}

Затем в моих циклах мне нужно было создать данные формы, которые я использовал

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

Спасибо ... Это полностью спасло меня! this. $ refs ['listView' + index] .nativeView.animate ({..}) Мне нужны переменные внутри ссылок, как это. $ refs.listView1 listView2 и так далее ...
Meiki Neumann

2

Это альтернатива для тех, кому нужно экспортировать переменную с динамическим именем

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

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

Другая альтернатива - просто создать объект, ключи которого называются динамически.

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

// consume it like this
vars[someVariable];

1

что они имеют в виду, нет, вы не можете. нет способа сделать это. так что можно было сделать что-то вроде этого

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

}

иметь функцию создания, аналогичную той, что реализована в ECMAScript 5.


4
Осторожно: const является ключевым словом в ES6
Tejas Manohar

4
... и до этого было будущее зарезервированное слово .
TJ Crowder

есть evalоператор
Pery Mimon

1

eval () не работал в моих тестах. Но добавление нового кода JavaScript в дерево DOM возможно. Итак, вот функция, которая добавляет новую переменную:

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
небольшое улучшение, то лучше использовать var node_head = document.getElementsByTagName("head")[0]вместо ID, так как никто не дает оценку id="head"для <head>:-)
ddlab

Я делаю :) Но спасибо, теперь я могу наконец удалить эту вещь "id =" head "
Аксель Хейдер

1
Это просто кажется слишком сложным способом создания глобальной переменной ?! (... и как это отвечает на вопрос?)
MrWhite

гений :) Eval является решением. Даже если ваш код не работает
Pery Mimon

1

Хотя у этого есть принятый ответ, я хотел бы добавить наблюдение:

В ES6 использование let не работает :

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

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

Однако использование var работает

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

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

Я надеюсь, что это может быть полезно для некоторых.


1
то же самое относится кconst

1
Правда. Но вы можете создать объект с переменными и выберите переменную оттуда: const vars = { t, m, b }; console.log(vars['b']). Иначе evalтоже работает.
Фабиан фон Эллертс

0

использовать объект тоже здорово.

var a=123
var b=234
var temp = {"a":a,"b":b}
console.log(temp["a"],temp["b"]);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.