Використовуйте імена динамічних змінних у 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;

У глобальній області (= контекст функції NO) ви неявно записуєте ці змінні в об’єкт Global (= 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
Але що робити, якщо моя динамічна змінна є локальною у функції? наприклад: function boink () {var a = 1; // це не буде працювати var dynam = this ['a']; // це також не буде працювати var dinami = ['a']; }
Кокодоко

@ Kokodoko - оскільки це не "контекст" або посилання на контекст виконання функції (немає способу посилання на контекст виконання, це заборонено ECMA-262). це встановлюється тим, як функція викликається (або прив'язується ), це просто Об'єкт, який не має нічого спільного з контекстом виконання, в якому він доступний.
RobG

Якщо вам потрібно отримати доступ до вкладених властивостей, перегляньте stackoverflow.com/questions/4244896/…
пан Бр

вказав на мене в правильному напрямку нотацією дужки. Застрягла лише мислення крапка.
Андрій

149

eval є одним із варіантів.

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

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

19
Ні, це не повинно, бо евал є злом. Ніколи не використовуйте 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) Що робити, якщо a 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. І саме так пояснюється "складна відповідь".
Орафу

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

Спробуйте це...


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 ви можете використовувати той факт, що всі властивості є ключовими парами значень. jAndy вже згадував про це, але я не думаю, що його відповідь показує, як це можна використовувати.

Зазвичай ви не намагаєтеся створити змінну для утримання імені змінної, але намагаєтесь генерувати імена змінних, а потім використовуєте їх. 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 = {}; у циклі .... для (var i = 0; i <= 3; i ++) {someJsonObj [i] = []; }, але я можу бути чим завгодно. настільки динамічно генеровані змінні, всі сидять усередині деякихJsonObj для зручності.
rajeev

5

2019 рік

TL; DR

  • eval оператор може запускати рядкове вираження в контексті, який він викликав, і повертати змінні з цього контексту;
  • literal objectтеоретично це можна зробити, записавши:, {[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дуже сильний але я впевнений, що ви це вже знаєте

BTW, якщо це було законно, ми могли б використовувати literal objectдля захоплення ім'я змінної та значення змінної, але ми не можемо поєднувати обчислені імена властивостей та скорочення значення властивості, на жаль, недійсне

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

    var capture = {[varName]}

}

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

Це швидке рішення, але це погана практика, оскільки це не безпечно і знижує продуктивність, оскільки двигун JS не може оптимізувати цей метод.
Дієго Ортіз

Дивовижне рішення
Rohit Parte

4

Якщо ви не хочете використовувати такий глобальний об’єкт, як вікно або global (вузол), ви можете спробувати щось подібне:

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

Дякую ... Це мене повністю врятувало! $. 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
Манохар

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
Це просто здається надто складним способом створення глобальної змінної ?! (... і як це відповідає на питання?)
Містер Білий

геній :) 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.