ใช้ชื่อตัวแปรแบบไดนามิกใน 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
dupe ที่เป็นไปได้ของstackoverflow.com/questions/724857/ …และstackoverflow.com/questions/1664282/…แต่คำตอบที่ยอมรับได้ดีกว่า IMO
goodeye

นี่ตอบคำถามของคุณหรือไม่? ตัวแปร "Variable" ใน Javascript? . คำตอบที่ได้รับการยอมรับว่ามีดีกว่าที่นี่เพราะมันแสดงให้เห็นถึงวิธีที่จะทำ แต่ยังถูกต้องเตือนว่ามีเกือบเสมอวิธีที่ดีกว่าที่จะทำสิ่งที่เป็นคุณต้องการที่จะทำ ดูปัญหา XYในเมตาดาต้า
ggorlen

คำตอบ:


354

เนื่องจาก ECMA- / Javascript เป็นข้อมูลเกี่ยวกับObjectsและContexts(ซึ่งเป็นบางส่วนของ Object) ตัวแปรทุกตัวจึงถูกเก็บไว้ในตัวแปรที่เรียกว่า(หรือในกรณีของ Function, Activation Object )

ดังนั้นถ้าคุณสร้างตัวแปรเช่นนี้:

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

ในขอบเขตส่วนกลาง (= ไม่มีบริบทของฟังก์ชัน) คุณเขียนตัวแปรเหล่านั้นลงในวัตถุ Global (= windowในเบราว์เซอร์) โดยปริยาย

สามารถเข้าถึงได้โดยใช้เครื่องหมาย "dot" หรือ "bracket":

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จะถูกเก็บไว้ใน Activation Object foobarซึ่งเราไม่สามารถเข้าถึงได้ (แน่นอนว่าเราสามารถเข้าถึงได้โดยตรงโดยการโทรaและb)


1
อีกสิ่งที่ยอดเยี่ยมคือด้วยวิธีนี้คุณสามารถเพิ่มการโทรกลับ (เริ่มต้น / สิ้นสุด) สำหรับฟังก์ชันระดับโลก
พิษ

5
แต่ถ้าตัวแปรแบบไดนามิกของฉันอยู่ภายในฟังก์ชัน ตัวอย่างเช่น function boink () {var a = 1; // นี่จะไม่ทำงาน var dynamic = this ['a']; // สิ่งนี้จะไม่ทำงาน var dynamic = ['a']; }
Kokodoko

@ Kokodoko - เพราะนี่ไม่ใช่ "บริบท" หรือการอ้างอิงถึงบริบทการดำเนินการของฟังก์ชั่น (ไม่มีวิธีการอ้างอิงบริบทการดำเนินการมันถูกห้ามโดย ECMA-262) สิ่งนี้ถูกกำหนดโดยวิธีการเรียกใช้ฟังก์ชัน (หรือโดยการผูก ) มันเป็นเพียงวัตถุที่ไม่เกี่ยวข้องกับบริบทการดำเนินการที่สามารถเข้าถึงได้
RobG

หากคุณต้องการเข้าถึงคุณสมบัติที่ซ้อนกันให้ตรวจสอบstackoverflow.com/questions/4244896//
นาย Br

ชี้ไปในทิศทางที่ถูกต้องพร้อมสัญกรณ์วงเล็บ ติดอยู่กับการคิดเครื่องหมายจุดเท่านั้น
Andrew

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 ซึ่งมี vars ที่แท้จริงอยู่ในนั้นจากนั้นใช้ 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 คลุมเครือ thisthis
MrWhite

1
แต่ภายในของฟังก์ชั่นที่คุณไม่สามารถใช้thisหรือสิ่งอื่นในการเข้าถึงตัวแปรtypeจากตัวอย่างของคุณถ้าคุณมีชื่อในตัวแปรอื่น: function test(vname) { var type = 'article'; this[vname] = 'something else'; alert(type); }; test('type')จะแสดงไม่ได้article something elseและนั่นคือสิ่งที่ "คำตอบที่ซับซ้อน" อธิบาย
Orafu


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กลายเป็นตัวแปรโกโก้

เนื่องจากตัวแปรทั้งหมดในขอบเขตส่วนกลางเป็นคุณสมบัติของวัตถุหน้าต่าง


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] = []; } แต่ฉันสามารถเป็นอะไรก็ได้ ตัวแปรที่สร้างขึ้นแบบไดนามิกนั้นทั้งหมดอยู่ใน someJsonObj เพื่อการอ้างอิงที่ง่าย
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 ไม่สามารถปรับวิธีนั้นให้เหมาะสม
Diego Ortiz

ทางออกที่ดีเลิศ
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);

ขอบคุณ ... มันช่วยฉันโดยสิ้นเชิง! $ refs ['listView' + index] .nativeView.animate ({.. }) ฉันต้องการ vars ภายใน refs แบบนี้ $ 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="head"ไป<head>:-)
ddlab

ฉันทำ :) แต่ขอบคุณตอนนี้ฉันสามารถลบ `id =" head "สิ่งนี้ได้ในที่สุด
Axel Heider

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ทำงานเกินไป
Fabian von Ellerts

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.