Używaj nazw zmiennych dynamicznych w JavaScript

344

W PHP możesz robić niesamowite / przerażające rzeczy, takie jak:

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

Czy jest jakiś sposób na zrobienie czegoś takiego za pomocą Javascript?

Na przykład, jeśli mam, var name = 'the name of the variable';czy mogę uzyskać odwołanie do zmiennej o nazwie name?

Finbarr
źródło
2
Możliwe dupe stackoverflow.com/questions/724857 /... i stackoverflow.com/questions/1664282/... , ale lepiej zaakceptowana odpowiedź tutaj, IMO.
goodeye
Czy to odpowiada na twoje pytanie? Zmienne „zmienne” w JavaScript? . Przyjęta odpowiedź jest lepsza niż ta tutaj, ponieważ pokazuje, jak to zrobić, ale także poprawnie ostrzega, że ​​prawie zawsze istnieje lepszy sposób na robienie tego, co chcesz . Zobacz problem XY na meta.
ggorlen

Odpowiedzi:

354

Ponieważ chodzi o ECMA- / Javascript Objectsi Contexts(które są również jakimś przedmiotem Object), każda zmienna jest przechowywana w tak zwanej Zmiennej (lub w przypadku Funkcji, Aktywacji Obiekt ).

Więc jeśli utworzysz zmienne takie jak to:

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

W zakresie globalnym (= kontekst funkcji NO) niejawnie zapisujesz te zmienne w obiekcie globalnym (= windoww przeglądarce).

Można do nich uzyskać dostęp za pomocą notacji „kropka” lub „nawias”:

var name = window.a;

lub

var name = window['a'];

To działa tylko dla globalnego obiektu w tym konkretnym przypadku, ponieważ zmienna obiektu na obiekt globalny jest windowsam obiekt. W kontekście funkcji nie masz bezpośredniego dostępu do obiektu aktywacyjnego . Na przykład:

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

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

new foobar();

newtworzy nową instancję samodzielnie zdefiniowanego obiektu (kontekstu). Bez newzakresu funkcji byłoby również global(= okno). Ten przykład odpowiednio ostrzegłby undefinedi 1. Gdybyśmy zastąpili this.a = 1; this.b = 2:

var a = 1,
    b = 2;

Oba wyjścia alarmowe byłyby niezdefiniowane. W tym scenariuszu zmienne ai bbyłyby przechowywane w obiekcie aktywacyjnym, z foobarktórego nie mamy dostępu (oczywiście moglibyśmy uzyskać do nich bezpośredni dostęp poprzez wywołanie ai b).

jAndy
źródło
1
Kolejną fajną rzeczą jest to, że w ten sposób można dodać funkcję zwrotną (początek / koniec) dla dowolnej funkcji poziomu globalnego.
antytoksyczny
5
Ale co jeśli moja zmienna dynamiczna jest lokalna w funkcji? na przykład: function boink () {var a = 1; // to nie zadziała var dynamic = this ['a']; // to również nie zadziała var dynamic = ['a']; }
Kokodoko,
@ Kokodoko-bo to nie jest „kontekst” lub odniesienie do kontekstu wykonania funkcji użytkownika (nie ma sposobu, aby odwoływać się do kontekstu wykonania, to jest zakazane przez ECMA-262). ten jest ustalany przez jaki funkcja nazywa się (lub wiążą ), to po prostu obiekt, który nie ma nic wspólnego z kontekstu wykonania, w których jest to dostępne.
RobG
Jeśli chcesz uzyskać dostęp do zagnieżdżonych właściwości, sprawdź stackoverflow.com/questions/4244896/...
Mr Br
wskazał mi właściwy kierunek z notacją w nawiasie. Utknąłem tylko myślenie kropkowe.
Andrew
149

eval jest jedną z opcji.

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

document.write(eval(name)); // 1
erickb
źródło
19
Nie, nie powinno tak być, ponieważ ewolucja jest zła. Nigdy nie używaj eval!
EasyBB
52
@ EasyBB - jeśli masz zamiar powiedzieć, aby nigdy nie używać czegoś, nie pomagam wyjaśnić, dlaczego. Mam sytuację, w której nie mogę wymyślić innego sposobu na osiągnięcie tego, co robię, niż eval ()
Rampant Creative Group
4
Eval stanowi ryzyko ataków na użytkowników końcowych, a my nie będziemy technicznie źli, raczej źle zrozumiani i niewłaściwie wykorzystywani w przypadkach przegranych. Widziałem odpowiedzi php, które zawierają dosłowne zmienne, a następnie używają eval do uruchomienia. Chociaż nie należy tego używać w tym przypadku, ponieważ istnieją lepsze metody. Nie należy w ogóle używać tego pytania, ponieważ istnieją ogólnie lepsze metody i jestem pewien, że wielu z nas o tym wie.
EasyBB,
2
Via javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval --- „Rozważmy argumenty najczęściej wypowiadane przeciwko użyciu eval: 1) Wymaga kompilacji i dlatego jest powolny 2) Co jeśli złośliwy skrypt znalazł drogę do argumentu eval? 3) Wygląda brzydko 4) Dziedziczy kontekst wykonania i to wiązanie zakresu, w którym został wywołany ”
mattLummus
1
Oto jak tworzyć zmienne dynamiczne za pomocą eval: stackoverflow.com/a/13291766/5528600
am2124429
80

Możesz do tego użyć obiektu okna.

window['myVar']

window zawiera odniesienie do wszystkich używanych zmiennych globalnych i funkcji globalnych.

JohnP
źródło
28
I nie trzeba dodawać, że ten jest bezpieczniejszy niż eval ().
Cray
45

Tylko nie wiem, jak zła odpowiedź dostaje tyle głosów. Odpowiedź jest dość łatwa, ale komplikujesz ją.

// 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
źródło
13
„w funkcji, której używamy this” - Jeśli chcesz uzyskać dostęp do zmiennej globalnej w ten sposób, lepiej jest być jawnym i używać windowobiektu, a nie this. thisjest dwuznaczny.
MrWhite
1
Ale wewnątrz funkcji nie można użyć thisani nic innego, aby uzyskać dostęp do zmiennej typez twojego przykładu, jeśli masz jej nazwę w innej zmiennej: function test(vname) { var type = 'article'; this[vname] = 'something else'; alert(type); }; test('type')pokaże article, nie something else. I to wyjaśnia „złożona odpowiedź”.
Orafu
28
a = 'varname';
str = a+' = '+'123';
eval(str)
alert(varname);

Spróbuj tego...

amitchd
źródło
27

To jest przykład :

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

Inny przykład :

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

alert(coco); // display : riko

Zatem wartość „ coco ” w myVariable staje się zmienną coco .

Ponieważ wszystkie zmienne w zakresie globalnym są właściwościami obiektu Window.

Azodium
źródło
14

W Javascripcie możesz użyć faktu, że wszystkie właściwości są parami klucz-wartość. jAndy już o tym wspomniał, ale nie sądzę, aby jego odpowiedź wskazywała, jak można go wykorzystać.

Zwykle nie próbujesz utworzyć zmiennej do przechowywania nazwy zmiennej, ale próbujesz wygenerować nazwy zmiennych, a następnie użyć ich. PHP robi to z $$varnotacją, ale JavaScript nie musi tego robić, ponieważ klucze właściwości są wymienne z kluczami tablic.

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

daje 123. Zwykle chcesz skonstruować zmienną, dlatego istnieje pośredni charakter, więc możesz to zrobić na odwrót.

var mine = {};
mine.abc = 123;
console.log(mine["a"+"bc"]);
David Newcomb
źródło
1
var someJsonObj = {}; w pętli .... for (var i = 0; i <= 3; i ++) {someJsonObj [i] = []; }, ale mogę być kimkolwiek. więc dynamicznie generowane zmienne, wszystkie znajdują się wewnątrz jakiegoś JsonObj dla łatwego odniesienia.
rajeev
5

2019

TL; DR

  • eval operator może uruchamiać wyrażenie łańcuchowe w kontekście, który wywołuje i zwraca zmienne z tego kontekstu;
  • literal objectteoretycznie może to zrobić przez zapis:, {[varName]}ale z definicji jest zablokowane.

Natrafiam więc na to pytanie i wszyscy tutaj bawią się bez rzeczywistego rozwiązania. ale @Axel Heider ma dobre podejście.

Rozwiązaniem jest eval. prawie najbardziej zapomniany operator. (myślę, że większość z nich jest with())

evaloperator może dynamicznie uruchamiać wyrażenie w kontekście, który wywołał. i zwróć wynik tego wyrażenia. możemy tego użyć, aby dynamicznie zwrócić wartość zmiennej w kontekście funkcji.

przykład:

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

Zauważ, że zawsze piszę jawnie, wyrażenie evalbędzie działać. Aby uniknąć niepotrzebnych niespodzianek w kodzie. evaljest bardzo silny, ale jestem pewien, że już o tym wiesz

BTW, gdyby było to zgodne z prawem, moglibyśmy użyć literal objectdo przechwycenia nazwy i wartości zmiennej, ale nie możemy łączyć obliczonych nazw właściwości i wartości nieruchomości w skrócie

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

    var capture = {[varName]}

}

example('var1') //trow 'Uncaught SyntaxError: Unexpected token }`
pery mimon
źródło
Jest to szybkie rozwiązanie, ale jest to zła praktyka, ponieważ nie jest bezpieczne i obniża wydajność, ponieważ silnik JS nie może zoptymalizować tej metody.
Diego Ortiz
Niesamowite rozwiązanie
Rohit Parte
4

Jeśli nie chcesz używać obiektu globalnego, takiego jak okno lub globalny (węzeł), możesz wypróbować coś takiego:

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

console.log(obj['whatever']);
Brent Barbata
źródło
4

Musiałem narysować wiele FormData w locie, a sposób obiektowy działał dobrze

var forms = {}

Następnie w moich pętlach, gdziekolwiek musiałem utworzyć dane formularza, których użyłem

forms["formdata"+counter]=new FormData();
forms["formdata"+counter].append(var_name, var_value);
Talha
źródło
Dzięki ... Całkowicie mnie uratowało! this. $ refs ['listView' + index] .nativeView.animate ({..}) Potrzebowałem zmiennych wewnątrz takich referencji jak to. $ refs.listView1 listView2 i tak dalej ...
Meiki Neumann
2

Jest to alternatywa dla tych, którzy muszą wyeksportować zmienną o nazwie dynamicznej

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

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

Inną alternatywą jest po prostu utworzenie obiektu, którego klucze są nazywane dynamicznie

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

// consume it like this
vars[someVariable];
JeanAlesi
źródło
1

mają na myśli nie, nie możesz. nie ma sposobu, aby to zrobić. więc możliwe było zrobienie czegoś takiego

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

}

posiadające funkcję tworzenia podobną do tej zaimplementowanej w ECMAScript 5.

Alfgaar
źródło
4
Uwaga: const jest słowem kluczowym w ES6
Tejas Manohar,
4
... a wcześniej było to zastrzeżone słowo na przyszłość .
TJ Crowder,
jest evaloperator
pery mimon
1

eval () nie działał w moich testach. Możliwe jest jednak dodanie nowego kodu JavaScript do drzewa DOM. Oto funkcja dodająca nową zmienną:

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
źródło
2
niewielka poprawa, lepiej jest używać var node_head = document.getElementsByTagName("head")[0]zamiast identyfikatora, jak nikt nie przywiązuje się id="head"do <head>:-)
ddlab
Robię :) Ale dzięki, teraz mogę w końcu usunąć to `id =" head "
Axel Heider
1
To wydaje się być zbyt skomplikowanym sposobem tworzenia zmiennej globalnej ?! (... i jak to odpowiada na pytanie?)
MrWhite
geniusz :) eval jest rozwiązaniem. Nawet jeśli kod nie działa
pery mimon
1

Chociaż mam zaakceptowaną odpowiedź, chciałbym dodać spostrzeżenie:

W ES6 używanie let nie działa :

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

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

Jednak korzystanie var działa

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

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

Mam nadzieję, że może to być przydatne dla niektórych.

enxaneta
źródło
1
to samo dotyczyconst
1
Prawdziwe. Ale można utworzyć obiekt ze zmiennych i wybrać zmienną stamtąd: const vars = { t, m, b }; console.log(vars['b']). W przeciwnym razie evaldziała również.
Fabian von Ellerts
0

użycie Object jest również świetne.

var a=123
var b=234
var temp = {"a":a,"b":b}
console.log(temp["a"],temp["b"]);
Steve Jiang
źródło