Javascript ใช้ตัวแปรเป็นชื่อวัตถุ


92

ฉันต้องการใช้ค่าของตัวแปรเพื่อเข้าถึงวัตถุ

สมมติว่าฉันมีวัตถุชื่อ myobject

ฉันต้องการเติมตัวแปรด้วยชื่อนี้และใช้ตัวแปรเพื่อเข้าถึงวัตถุ

ตัวอย่าง:

var objname = 'myobject';
{objname}.value = 'value';

คำตอบ:


126

ทั่วโลก:

myObject = { value: 0 };
anObjectName = "myObject";
this[anObjectName].value++;

console.log(this[anObjectName]);

ทั่วโลก: v2.0

var anObjectName = "myObject";
this[anObjectName] = "myvalue"

console.log(myObject)

ในเครื่อง: v1.2

(function() {
    var scope = this;

    if (scope != arguments.callee) {
        arguments.callee.call(arguments.callee);
        return false;
    }

    scope.myObject = { value: 0 };
    scope.anObjectName = "myObject";
    scope[scope.anObjectName].value++;

    console.log(scope.myObject.value);
})();

ท้องถิ่น: v2.0

(function() {  
    var scope = this;

    scope.myObject = { value: 0 };
    scope.anObjectName = "myObject";
    scope[scope.anObjectName].value++;

    console.log(scope.myObject.value);    
}).call({});

@Shaz - (. alert(this === window)สมมติว่าพวกเขาจะดำเนินการในเบราว์เซอร์)
Sean Vieira

1
@PeeHaa - The ท้องถิ่นเช่นชุดตัวแปรที่windowวัตถุที่เรียกว่าobjnameซึ่งมีการอ้างอิงแล้วผ่านthis... คุณสามารถใช้แทนwindowสำหรับthisในตัวอย่างที่สองและทุกอย่างจะยังคงทำงาน :-)
Sean Vieira

1
@SeanVieira: ดูตัวอย่างที่อัปเดต หวังว่าตอนนี้จะใช้งานได้ถูกต้อง
Shaz

1
@Shaz - arguments.calleeเลิกใช้งานแล้ว แต่มันเป็นการใช้งานที่ชาญฉลาดมาก - และมันก็ไม่ได้ส่งผลกระทบต่อขอบเขตทั่วโลก +1
Sean Vieira

1
อาจไม่ก่อให้เกิดมลพิษต่อขอบเขตทั่วโลก แต่เป็นการสร้างวัตถุที่ใช้ร่วมกันในทุกการเรียกใช้ฟังก์ชัน ฟังก์ชันของคุณถือobjnameเป็นคุณสมบัติของฟังก์ชันเอง อาจล้มเหลวสำหรับฟังก์ชันเรียกซ้ำ ไม่แน่ใจว่าสิ่งนี้สามารถใช้ในโลกแห่งความเป็นจริงได้อย่างไร
Juan Mendes

31

ใช้วงเล็บเหลี่ยมรอบชื่อตัวแปร

var objname = 'myobject';
{[objname]}.value = 'value';

7
นี่เป็นสิ่งที่สมบูรณ์แบบและเรียบง่ายและควรเป็นคำตอบอันดับต้น ๆ
Brad

5
สิ่งนี้ทำให้เกิดข้อยกเว้น: SyntaxError: นิพจน์ที่คาดหวังได้รับ "." มันไม่ทำงาน; ทำไมโหวตเยอะจัง
Lovro

9

เป็นตัวแปรระดับโลกหรือไม่? ถ้าเป็นเช่นนั้นเหล่านี้เป็นจริงส่วนหนึ่งของวัตถุเพื่อให้คุณสามารถทำwindowwindow[objname].value

ถ้าเป็นฟังก์ชันเฉพาะที่ฉันคิดว่าไม่มีวิธีที่ดีในการทำสิ่งที่คุณต้องการ


8

วัตถุมีอยู่ในขอบเขตบางส่วนดังนั้นคุณจึงสามารถเข้าถึงตัวแปรได้เกือบตลอดเวลาผ่านทางไวยากรณ์นี้:

var objname = "myobject";
containing_scope_reference[objname].some_property = 'some value';

สถานที่เดียวที่จะยุ่งยากคือเมื่อคุณอยู่ในขอบเขตปิดและคุณต้องการเข้าถึงตัวแปรท้องถิ่นระดับบนสุด เมื่อคุณมีสิ่งนี้:

(function(){
    var some_variable = {value: 25};
    var x = "some_variable";
    console.log(this[x], window[x]); // Doesn't work
})();

คุณสามารถหลีกเลี่ยงสิ่งนั้นได้โดยใช้evalแทนเพื่อเข้าถึงห่วงโซ่ขอบเขตปัจจุบัน ... แต่ฉันไม่แนะนำให้ทำเว้นแต่คุณจะได้ทำการทดสอบมากมายและคุณรู้ว่านั่นเป็นวิธีที่ดีที่สุดในการทำสิ่งต่างๆ

(function(){
    var some_variable = {value: 25};
    var x = "some_variable";
    eval(x).value = 42;
    console.log(some_variable); // Works
})();

ทางออกที่ดีที่สุดของคุณคือการอ้างอิงถึงชื่อในออบเจ็กต์ที่จะมีให้เกิดขึ้นตลอดเวลา (เช่นthisในขอบเขตส่วนกลางหรือตัวแปรระดับบนสุดส่วนตัวในขอบเขตท้องถิ่น) และใส่ทุกอย่างลงไป

ดังนั้น:

var my_outer_variable = {};
var outer_pointer = 'my_outer_variable';
// Reach my_outer_variable with this[outer_pointer]
// or window[outer_pointer]

(function(){
    var my_inner_scope = {'my_inner_variable': {} };
    var inner_pointer = 'my_inner_variable';
    // Reach my_inner_variable by using
    // my_inner_scope[inner_pointer]
})();

7

คุณสามารถใช้eval:

eval(variablename + ".value = 'value'");

ไม่evalถือว่าevil? ถ้าไม่ฉันอาจใช้มัน เพราะตอนนี้มันเป็นแบบสากล แต่ฉันอยากจะย้ายไปไว้ในฟังก์ชันเพื่อล้างข้อมูล
PeeHaa

1
ฮ่า ๆ. หากชื่อตัวแปรมาจากการป้อนข้อมูลของผู้ใช้ตรวจสอบให้แน่ใจว่าคุณได้ตรวจสอบความถูกต้องเพื่อไม่ให้มีโค้ด JS ที่evalสามารถเรียกใช้งานได้
Midas

1
นี่เป็นหนึ่งในการใช้งานที่ถูกต้องตามกฎหมายevalในความคิดของฉัน เราต้องแน่ใจว่าตัวแปรนั้นสะอาด
Levi Morrison

2
ใช่มันไม่ใช่ปัญหาจริงๆ แต่ลองดูคำตอบจาก Shaz ฉันคิดว่านั่นเป็นทางออกที่สะอาดกว่า
Midas

2
@PeeHaa: ถ้าคุณคิดจะย้ายมันทำไมไม่ย้ายมันไปอยู่ในทรัพย์สินของวัตถุที่เป็นที่รู้จักแล้วคุณจะทำอะไรได้myVar[objname].valueบ้าง?
.

6

คุณไม่สามารถทำได้โดยทั่วไปยกเว้นที่ขอบเขตหน้าต่างซึ่งคุณสามารถเขียนได้ window[objname].value = 'value';


4

ฉันคิดว่าคำตอบของ Shaz สำหรับตัวแปรท้องถิ่นนั้นยากที่จะเข้าใจแม้ว่าจะใช้ได้กับฟังก์ชันที่ไม่เรียกซ้ำ นี่เป็นอีกวิธีหนึ่งที่ฉันคิดว่ามันชัดเจนขึ้น (แต่ก็ยังคงเป็นความคิดของเขาพฤติกรรมเหมือนเดิมทุกประการ) นอกจากนี้ยังไม่ได้เข้าถึงตัวแปรภายในแบบไดนามิกเป็นเพียงคุณสมบัติของตัวแปรโลคัล

โดยพื้นฐานแล้วมันใช้ตัวแปรส่วนกลาง (แนบกับวัตถุฟังก์ชัน)

// Here's  a version of it that is more straight forward.
function doIt() {
    doIt.objname = {};
    var someObject = "objname";
    doIt[someObject].value = "value";    
    console.log(doIt.objname);
})();

ซึ่งโดยพื้นฐานแล้วจะเหมือนกับการสร้าง global เพื่อจัดเก็บตัวแปรดังนั้นคุณจึงสามารถเข้าถึงเป็นคุณสมบัติได้ การสร้างทั่วโลกเพื่อทำเช่นนี้เป็นการแฮ็ก

นี่คือแฮ็คที่สะอาดกว่าซึ่งไม่ได้สร้างตัวแปรส่วนกลาง แต่จะใช้ตัวแปรภายในแทน

function doIt() {
  var scope = {
     MyProp: "Hello"
  };
  var name = "MyProp";
  console.log(scope[name]);
}

ดูJavascript: ตีความ string เป็นการอ้างอิงวัตถุ?


2
let players = [];
players[something] = {};
players[something].somethingElse = 'test';
console.log(players); 

-> [บางสิ่ง: {somethingElse: 'test'}];


1

ถ้าออบเจ็กต์อยู่ในเนมสเปซเช่น. Company.Module.Components.Fooคุณสามารถใช้ฟังก์ชันนี้:

CoffeeScript:

objByName: (name, context = window) ->
    ns = name.split "."
    func = context
    for n, i in ns
        func = func[n]
    return func

ผลลัพธ์ Js:

objByName: function(name, context) {
  var func, i, n, ns, _i, _len;
  if (context == null) {
    context = window;
  }
  ns = name.split(".");
  func = context;
  for (i = _i = 0, _len = ns.length; _i < _len; i = ++_i) {
    n = ns[i];
    func = func[n];
  }
  return func;
}

จากนั้นคุณสามารถสร้างวัตถุใหม่หรือทำอะไรก็ได้ สังเกตวงเล็บผ่าน

var o = new (objByName('Company.Module.Components.Foo'))
objByName('some.deeply.nested.object').value

แนวคิดนี้ยืมมาจากคำถามที่คล้ายกัน: วิธีเรียกใช้ฟังก์ชัน JavaScript เมื่อฉันมีชื่อเป็นสตริง


0

เมื่อใช้หน้าต่าง [objname] โปรดตรวจสอบว่า objname เป็นตัวแปรส่วนกลาง มิฉะนั้นจะทำงานบางครั้งและล้มเหลวในบางครั้ง window [objname] .value.


0

ความท้าทายอย่างหนึ่งที่ฉันมีกับคำตอบคือการสันนิษฐานว่าวัตถุนั้นเป็นระดับเดียว ตัวอย่างเช่น,

const testObj = { testKey: 'testValue' }
const refString = 'testKey';
const refObj = testObj[refString];

ใช้งานได้ดี แต่

const testObj = { testKey:
                  { level2Key: 'level2Value' }
                }
const refString = 'testKey.level2Key';
const refObj = testObj[refString];

ไม่ทำงาน, ไม่เป็นผล.

สิ่งที่ฉันทำคือการสร้างฟังก์ชันเพื่อเข้าถึงวัตถุหลายระดับ:

objVar(str) {
    let obj = this;
    const parts = str.split('.');
    for (let p of parts) {
        obj = obj[p];
    }
    return obj;
}

ในสถานการณ์ที่สองฉันสามารถส่งสตริงไปยังฟังก์ชันนี้เพื่อเรียกคืนวัตถุที่ฉันกำลังมองหา:

const testObj = { testKey:
                  { level2Key: 'level2Value' }
                }
const refString = 'testObj.testKey.level2Key';
const refObj = objVar[refString];


0

หากคุณทราบรายชื่อตัวแปรที่เป็นไปได้แล้วให้ลองสร้าง Object (iconObj) ใหม่ที่มีชื่อคุณสมบัติเหมือนกับชื่ออ็อบเจ็กต์ในตัวอย่างด้านล่างตัวแปร iconLib จะเก็บค่าสตริงสองค่าไม่ว่าจะเป็น 'ZondIcons' หรือ 'MaterialIcons' . propertyName เป็นคุณสมบัติของวัตถุ ZondIcons หรือ MaterialsIcon

   const iconObj = {
    ZondIcons,
    MaterialIcons,
  }
  const objValue = iconObj[iconLib][propertyName]

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