JavaScript使用变量作为对象名称

106
我想使用变量的值来访问一个对象。 假设我有一个名为myobject的对象。 我想用这个名称填充一个变量,并使用该变量访问该对象。 示例:
var objname = 'myobject';
{objname}.value = 'value';
15个回答

138

全局变量:

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

console.log(this[anObjectName]);

全局变量: v2

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

console.log(myObject)

本地版本: v1

(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

(function() {  
    var scope = this;

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

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

1
@PeeHaa - Local 示例在 window 对象上设置了一个名为 objname 的变量,然后通过 this 引用它...你可以在第二个示例中将 window 替换为 this,一切仍将正常工作。 :-) - Sean Vieira
1
@SeanVieira:看一下更新后的示例。希望现在能正常工作。 - Shaz
1
@Shaz -- arguments.callee已经被弃用,但它仍然是一个非常聪明的实现方式--而且它不会污染全局作用域。+1 - Sean Vieira
1
它可能不会污染全局作用域,但它正在创建一个由函数的每次调用共享的对象。您的函数将objname保持为函数本身的属性。这可能会在递归函数中失败。不确定这在现实世界中如何使用。 - Ruan Mendes
@Sean @Juan,我已经更新了第二个版本,不再使用arguments.callee - Shaz
显示剩余3条评论

45

在变量名周围使用方括号。

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

7
这个答案完美简洁,应该成为最佳答案。 - Brad
11
这里抛出了一个异常:SyntaxError: expected expression, got '.'。它不能正常工作,为什么会有这么多赞? - Lovro
感谢您提供简单而完美的答案! - jbernardo
这就是我正在搜索的! - Quinten C

10

这是一个全局变量吗?如果是,它们实际上是 window 对象的一部分,因此您可以使用 window[objname].value.

如果它是函数内的局部变量,我认为没有好的方法可以做到你想要的。


9

对象存在于某个作用域中,因此您几乎可以始终通过以下语法访问变量:

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

8
您可以使用 eval 函数:
eval(variablename + ".value = 'value'");

“eval”不是被认为是“邪恶”的吗?如果不是,我可能会使用它。因为它现在是全局的,但我想将其移入一个函数中以清理一些东西。 - PeeHaa
1
哈哈。如果变量名来自用户输入,请确保对其进行验证,以防包含任何eval可以执行的JS代码。 - Midas
@Midas:它并不直接来自用户输入。而是来自HTML元素的数据内容。当然,用户可以操作该内容。但我不明白,如果用户可以执行自己的JS代码,有什么坏处呢?它只会在客户端上执行,难道我错了吗? - PeeHaa
1
这是我认为eval的少数合法用途之一。但我们必须确保变量是干净的。 - Levi Morrison
2
没错,这并不是真正的问题。但是看一下Shaz的答案吧,我认为那是一个更加简洁的解决方案。 - Midas
2
@PeeHaa:如果您正在考虑移动它,为什么不将其移动到已知对象的属性中,这样您就可以执行类似myVar[objname].value的操作? - JW.

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

这基本上与创建一个全局变量来存储变量并将其作为属性访问是相同的。创建全局变量是一种hack方法。

以下是一种更干净的hack方法,它不会创建全局变量,而是使用本地变量。

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

请查看Javascript: interpret string as object reference?


4

方括号可以用来使键变得动态,就像这样

var myObjKey = "key";

var obj = {[myObjKey] : "value" };
console.log(obj); // => {key: 'value'}

var anotherObj = {["justString"] : "value" };
console.log(anotherObj ); // => {justString: 'value'}

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

-> [ something: { 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函数

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接