Используйте имена динамических переменных в 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.