Sử dụng tên biến động trong JavaScript


344

Trong PHP bạn có thể làm những điều tuyệt vời / kinh khủng như thế này:

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

Có cách nào để làm một cái gì đó như thế này với Javascript không?

Ví dụ, nếu tôi có var name = 'the name of the variable';một tham chiếu đến biến có tên name?


2
Bản sao có thể có của stackoverflow.com/questions/724857/ , và stackoverflow.com/questions/1664282/ , nhưng câu trả lời được chấp nhận ở đây tốt hơn, IMO.
tạm biệt

Điều này có trả lời câu hỏi của bạn không? Biến "biến" trong Javascript? . Câu trả lời được chấp nhận ở đó tốt hơn câu trả lời ở đây vì nó chỉ ra cách thực hiện, nhưng cũng cảnh báo chính xác rằng hầu như luôn luôn là cách tốt hơn để làm bất cứ điều gì bạn muốn làm . Xem vấn đề XY trên meta.
ggorlen

Câu trả lời:


353

Vì ECMA- / Javascript là tất cả về ObjectsContexts(cũng là một số đối tượng của Đối tượng), mọi biến được lưu trữ trong một biến gọi là Biến (hoặc trong trường hợp của Hàm, Đối tượng Kích hoạt ).

Vì vậy, nếu bạn tạo các biến như thế này:

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

Trong phạm vi Toàn cầu (= bối cảnh hàm NO), bạn hoàn toàn viết các biến đó vào đối tượng Toàn cầu (= windowtrong trình duyệt).

Những người có thể được truy cập bằng cách sử dụng ký hiệu "dấu chấm" hoặc "dấu ngoặc":

var name = window.a;

hoặc là

var name = window['a'];

Điều này chỉ hoạt động cho đối tượng toàn cầu trong trường hợp cụ thể này, bởi vì Đối tượng biến của Đối tượng toàn cầuwindowchính đối tượng. Trong bối cảnh của một chức năng, bạn không có quyền truy cập trực tiếp vào Đối tượng kích hoạt . Ví dụ:

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

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

new foobar();

newtạo một thể hiện mới của một đối tượng tự xác định (bối cảnh). Nếu không có newphạm vi của hàm thì cũng sẽ global(= window). Ví dụ này sẽ cảnh báo undefined1tương ứng. Nếu chúng ta sẽ thay thế this.a = 1; this.b = 2bằng:

var a = 1,
    b = 2;

Cả hai đầu ra cảnh báo sẽ không được xác định. Trong kịch bản đó, các biến absẽ được lưu trữ trong Đối tượng kích hoạt foobarmà chúng ta không thể truy cập (tất nhiên chúng ta có thể truy cập trực tiếp vào các biến đó bằng cách gọi ab).


1
Một điều thú vị nữa là theo cách này bạn có thể thêm gọi lại (bắt đầu / kết thúc) cho bất kỳ chức năng cấp toàn cầu nào.
chống độc

5
Nhưng nếu biến động của tôi là cục bộ trong một hàm thì sao? ví dụ: hàm boink () {var a = 1; // cái này sẽ không hoạt động var Dynamic = this ['a']; // cái này cũng không hoạt động var Dynamic = ['a']; }
Kokodoko

@ Kokodoko, vì đây không phải là "bối cảnh" hoặc tham chiếu đến bối cảnh thực thi của hàm (không có cách nào để tham chiếu bối cảnh thực thi, nó bị cấm bởi ECMA-262). điều này được thiết lập bằng cách một hàm được gọi (hoặc bằng liên kết ), nó chỉ là một Đối tượng không liên quan gì đến bối cảnh thực thi mà nó có thể truy cập được.
RobG

Nếu bạn cần truy cập các thuộc tính lồng nhau, hãy kiểm tra stackoverflow.com/questions/4244896/ cấp
Mr Br

chỉ cho tôi đi đúng hướng với ký hiệu khung. Đã bị mắc kẹt chỉ nghĩ ký hiệu chấm.
Andrew

149

eval là một lựa chọn.

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

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

19
Không, nó không nên vì eval là xấu xa. Không bao giờ sử dụng eval!
EasyBB

52
@ EasyBB - nếu bạn định nói không bao giờ sử dụng thứ gì đó, tôi không hữu ích để giải thích lý do. Tôi có một tình huống mà tôi không thể nghĩ ra bất kỳ cách nào khác để thực hiện những gì tôi đang làm ngoài eval ()
Nhóm sáng tạo Rampant

4
Eval có nguy cơ tấn công người dùng cuối và chúng tôi sẽ không xấu xa về mặt kỹ thuật mà bị hiểu lầm và sử dụng sai trong trường hợp bị mất. Tôi đã thấy các phản hồi php chứa các bình chữ trong đó sau đó sử dụng eval để chạy nó. Mặc dù điều này không nên được sử dụng trong trường hợp này vì có những phương pháp tốt hơn. Câu hỏi này không nên được sử dụng vì có nhiều phương pháp tốt hơn và tôi chắc chắn rất nhiều người trong chúng ta biết điều này.
EasyBB

2
Thông qua javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval --- "Chúng ta hãy xem xét các đối số được phân cấp thường xuyên nhất khi sử dụng eval: 1) Nó yêu cầu biên dịch và do đó chậm 2) Điều gì xảy ra nếu a kịch bản độc hại tìm đường vào tranh luận eval? 3) Trông xấu xí 4) Nó thừa hưởng bối cảnh thực thi và ràng buộc của phạm vi mà nó được viện dẫn "
mattLummus

1
Dưới đây là cách tạo biến động bằng eval: stackoverflow.com/a/13291766/5528600
am2124429

80

Bạn có thể sử dụng đối tượng cửa sổ để lấy nó.

window['myVar']

window có một tham chiếu đến tất cả các biến toàn cục và các hàm toàn cầu bạn đang sử dụng.


28
Và không cần phải nói, cái này an toàn hơn eval ().
Cray

45

Chỉ không biết những gì một câu trả lời xấu nhận được nhiều phiếu bầu. Đó là câu trả lời khá dễ dàng nhưng bạn làm cho nó phức tạp.

// 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
"Trong một chức năng chúng tôi sử dụng this" - Nếu bạn muốn truy cập một biến toàn cục theo cách này, tốt hơn là nên rõ ràng và sử dụng windowđối tượng, không this. thislà mơ hồ.
MrWhite

1
Nhưng bên trong một hàm bạn không thể sử dụng this, hoặc bất cứ thứ gì khác, để truy cập biến typetừ ví dụ của bạn, nếu bạn có tên của nó trong một biến khác: function test(vname) { var type = 'article'; this[vname] = 'something else'; alert(type); }; test('type')sẽ hiển thị article, không something else. Và đó là những gì "câu trả lời phức tạp" giải thích.
Orafu

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

Thử cái này...


27

Đây là một ví dụ :

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

Một vi dụ khac :

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

alert(coco); // display : riko

Vì vậy, giá trị " coco " của myVariable trở thành một coco biến đổi .

Bởi vì tất cả các biến trong phạm vi toàn cục là thuộc tính của đối tượng Window.


14

Trong Javascript, bạn có thể sử dụng thực tế là tất cả các thuộc tính là các cặp giá trị chính. jAndy đã đề cập đến vấn đề này nhưng tôi không nghĩ câu trả lời của anh ấy cho thấy nó có thể được khai thác như thế nào.

Thông thường bạn không cố tạo một biến để giữ một tên biến nhưng đang cố tạo ra các tên biến và sau đó sử dụng chúng. PHP thực hiện với $$varký hiệu nhưng Javascript không cần vì các khóa thuộc tính có thể hoán đổi với các khóa mảng.

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

đưa ra 123. Thông thường bạn muốn xây dựng biến đó là lý do tại sao có sự gián tiếp để bạn cũng có thể thực hiện theo cách khác.

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

1
var someJsonObj = {}; trong một vòng lặp .... for (var i = 0; i <= 3; i ++) {someJsonObj [i] = []; }, nhưng tôi có thể là bất cứ điều gì. vì vậy các biến được tạo động, tất cả đều nằm trong someJsonObj để dễ dàng tham khảo.
rajeev

5

2019

TL; DR

  • eval toán tử có thể chạy biểu thức chuỗi trong ngữ cảnh mà nó gọi và trả về các biến từ ngữ cảnh đó;
  • literal objectvề mặt lý thuyết có thể làm điều đó bằng cách viết : {[varName]}, nhưng nó bị chặn theo định nghĩa.

Vì vậy, tôi bắt gặp câu hỏi này và mọi người ở đây chỉ chơi xung quanh mà không mang lại một giải pháp thực sự. nhưng @Axel Heider có cách tiếp cận tốt.

Giải pháp là eval. điều hành gần như bị lãng quên nhất. (nghĩ rằng hầu hết là một with())

evaltoán tử có thể tự động chạy biểu thức trong ngữ cảnh mà nó gọi. và trả về kết quả của biểu thức đó. chúng ta có thể sử dụng điều đó để tự động trả về giá trị của một biến trong ngữ cảnh của hàm.

thí dụ:

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

Lưu ý rằng tôi luôn viết rõ ràng biểu thức evalsẽ chạy. Để tránh những bất ngờ không cần thiết trong mã. evalrất mạnh Nhưng tôi chắc rằng bạn đã biết điều đó rồi

BTW, nếu đó là hợp pháp, chúng tôi có thể sử dụng literal objectđể nắm bắt tên và giá trị của biến, nhưng chúng tôi không thể kết hợp tên thuộc tính và giá trị tài sản tốc ký, đáng buồn thay, không hợp lệ

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

    var capture = {[varName]}

}

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

Đó là một giải pháp nhanh, nhưng đó là một thực tiễn tồi vì nó không an toàn và làm giảm hiệu suất do công cụ JS không thể tối ưu hóa phương thức đó.
Diego Ortiz

Giải pháp tuyệt vời
Rohit Parte

4

Nếu bạn không muốn sử dụng một đối tượng toàn cầu như cửa sổ hoặc toàn cầu (nút), bạn có thể thử một cái gì đó như thế này:

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

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

4

Tôi cần vẽ nhiều FormData một cách nhanh chóng và cách đối tượng hoạt động tốt

var forms = {}

Sau đó, trong các vòng lặp của tôi, bất cứ nơi nào tôi cần để tạo dữ liệu biểu mẫu tôi đã sử dụng

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

Cảm ơn ... Nó hoàn toàn cứu tôi! this. $ refs ['listView' + index] .nativeView.animate ({..}) Tôi cần vars bên trong refs như thế này. $ refs.listView1 listView2 và cứ thế ...
Meiki Neumann

2

Đây là một thay thế cho những người cần xuất một biến có tên động

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

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

Một cách khác là chỉ cần tạo một đối tượng có các khóa được đặt tên động

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

// consume it like this
vars[someVariable];

1

những gì họ có nghĩa là không, bạn không thể. không có cách nào để hoàn thành nó vì vậy có thể bạn có thể làm một cái gì đó như thế này

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

}

có chức năng tạo giống như chức năng được triển khai trong ECMAScript 5.


4
Coi chừng: const là một từ khóa trong ES6
Tejas Manohar

4
... và trước đó là một từ dành riêng trong tương lai .
TJ Crowder

evalnhà điều hành
pery mimon

1

eval () đã không làm việc trong các thử nghiệm của tôi. Nhưng việc thêm mã JavaScript mới vào cây DOM là có thể. Vì vậy, đây là một chức năng thêm một biến mới:

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
cải tiến nhỏ, nó là tốt hơn để sử dụng var node_head = document.getElementsByTagName("head")[0]thay vì ID, như không có ai đưa ra một id="head"để <head>:-)
ddlab

Tôi làm :) Nhưng cảm ơn, bây giờ tôi cuối cùng cũng có thể loại bỏ thứ 'id = "head" này
Axel Heider

1
Đây dường như là một cách quá phức tạp để tạo ra một biến toàn cục?! (... và làm thế nào để trả lời câu hỏi này?)
MrWhite

thiên tài :) eval là giải pháp. Ngay cả khi mã của bạn không hoạt động
pery mimon

1

Mặc dù điều này có một câu trả lời được chấp nhận, tôi muốn thêm một quan sát:

Trong ES6 sử dụng let không hoạt động :

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

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

Tuy nhiên sử dụng var công trình

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

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

Tôi hy vọng điều này có thể hữu ích cho một số.


1
áp dụng tương tự choconst

1
Thật. Nhưng bạn có thể tạo một đối tượng với các biến và chọn biến từ đó : const vars = { t, m, b }; console.log(vars['b']). Nếu không thì evallàm việc quá.
Fabian von Ellerts

0

sử dụng Object cũng rất tuyệt

var a=123
var b=234
var temp = {"a":a,"b":b}
console.log(temp["a"],temp["b"]);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.