如何在JavaScript对象字面量中使用变量作为键?

587

为什么以下代码有效?

<something>.stop().animate(
    { 'top' : 10 }, 10
);

然而,这个并不起作用:

var thetop = 'top';
<something>.stop().animate(
    { thetop : 10 }, 10
);
为了更清楚地表达:目前我无法将CSS属性作为变量传递给动画函数。

2
参见:使用动态键创建对象 - Bergi
谢谢。我正在搜索确切的东西。 - Siva-Dev-Wizard
这个回答解决了你的问题吗?JavaScript通过变量设置对象键 - Abdul Aziz Barkat
16个回答

902

{ thetop : 10 } 是一个有效的对象字面量。该代码将创建一个具有名为 thetop 的属性且值为10的对象。以下两者是相同的:

obj = { thetop : 10 };
obj = { "thetop" : 10 };
在ES5及之前的版本中,您无法在对象字面量中使用变量作为属性名称。您唯一的选择是执行以下操作:
var thetop = "top";

// create the object literal
var aniArgs = {};

// Assign the variable property name with a value of 10
aniArgs[thetop] = 10; 

// Pass the resulting object to the animate method
<something>.stop().animate(
    aniArgs, 10  
);  
ES6将ComputedPropertyName定义为对象字面量语法的一部分,允许您编写以下代码:

ComputedPropertyName

var thetop = "top",
    obj = { [thetop]: 10 };

console.log(obj.top); // -> 10

您可以在每个主流浏览器的最新版本中使用这种新语法。


我明白了!谢谢! 这个应该也可以用eval吧? 我的例子现在不行,但我认为它应该可以... :-) - speendo
3
@Marcel: eval() 在对象字面量中用于动态属性名是无法工作的,你只会得到一个错误。不仅如此,eval() 真的不应该用于这样的事情。有一篇关于 eval() 的正确和不正确用法的优秀文章:http://blogs.msdn.com/ericlippert/archive/2003/11/01/53329.aspx - Andy E
2
@AndyE 考虑更新“最近版本”和“当前IE TP”的一些更具体的时间,比如“XXX之后的版本”或“2014-mm之后”(我可以自己进行更改,但我不知道好的数值是什么)。 - Alexei Levenkov
1
对于ES6,如果key为null/undefined,是否有一种方法可以省略属性?例如,在{[key] : "value"}中,如果key为null,它会给出{ null: "value" },而我希望结果是{} - wasabigeek
很棒的解决方案,但是你怎么知道这么多,即使阅读整个规范也无法理解其中的要点:( - hugemeow

201

使用 ECMAScript 2015,您现在可以直接使用方括号符号在对象声明中进行操作:

var obj = {
  [key]: value
}
key 可以是任何类型的表达式(例如变量),返回一个值。 因此,您的代码将如下所示:
<something>.stop().animate({
  [thetop]: 10
}, 10)

在使用作为键之前,thetop将会被评估。


20

ES5引用,它表示不应该工作

注意:对于ES6已经更改了规则:https://dev59.com/jnE95IYBdhLWcg3wheRR#2274327

规范:http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5

PropertyName :

  • IdentifierName
  • StringLiteral
  • NumericLiteral

[...]

PropertyName : IdentifierName的产生方式如下:

  1. 返回包含与IdentifierName相同字符序列的字符串值。

PropertyName : StringLiteral的产生方式如下:

  1. 返回StringLiteral的字符串值SV。

PropertyName : NumericLiteral的产生方式如下:

  1. 将NumericLiteral的值形成为nbr。
  2. 返回ToString(nbr)。

这意味着:

  • { theTop : 10 }{ 'theTop' : 10 }完全相同

    PropertyName theTop 是一个IdentifierName,因此它被转换为 'theTop' 字符串值,这是'theTop'字符串值的字符串值。

  • 不可能使用变量键编写对象初始化程序(字面量)

    唯一的三个选项是 IdentifierName (扩展为字符串字面量)、StringLiteralNumericLiteral(也扩展为字符串)。


8
投票贬值者:我是第一个在这个问题中引用任何标准的人。顶部答案中的ES6引用是在我回答之后编辑的,并且当时该标准尚未被接受。如果您知道我为什么还会被贬值,请解释一下,我只是想学习。我也可能会获得同侪压力徽章…… - Ciro Santilli OurBigBook.com
1
我猜测你被踩的主要原因是你的回答没有提供解决方案,在这方面是“无用”的。投票受到同侪压力的影响 :-) - Bergi
3
@Bergi,感谢你的勇气! :-) 但我认为我已经直接回答了问题:问:“为什么以下代码有效?”答:“因为ES5规范如此规定。”“怎么做?”是隐含的。在ES6解决方案被编辑进来之前,你是否因为顶部的问题说“不可能”(没有标准引用)而将其投票反对? - Ciro Santilli OurBigBook.com
啊,好的。我通常会用块引用来引用特定的问题,以便清楚地回答它们。引用标准可以使一个好答案变得更好,但目前你的帖子甚至没有回答问题。说明ES5中可以制作关键字并不意味着它们是如何工作的。当然,thetop是一个IdentifierName,那么为什么它不起作用?这个问题仍然没有答案。 - Bergi
1
@Bergi 再次感谢您的解释!我已经更新了它,使其更加明确。之前我没有这样做是因为我认为这很明显,因为我们可以写{a:1}.a,所以在标识符情况下,a显然不会扩展变量值。但是,在这种情况下进一步解释是一个改进。 - Ciro Santilli OurBigBook.com

14

ES6 / 2020

如果你想要使用“键:值”从其他任何来源将数据推送到一个对象中,你可以使用类似以下的代码:

let obj = {}
let key = "foo"
let value = "bar"

obj[`${key}`] = value

// A `console.log(obj)` would return:
// {foo: "bar}

// A `typeof obj` would return:
// "object"

希望这能帮助到某些人 :)


obj[`some-prefix-${key}`] = value 这种写法也适用于希望灵活修改键变量的情况。结果将是 { some-prefix-foo: "bar" } - tinystone

6

我曾使用以下代码向一个对象添加一个“动态”的属性名:

var key = 'top';
$('#myElement').animate(
   (function(o) { o[key]=10; return o;})({left: 20, width: 100}),
   10
);

key 是新属性的名称。

传递给 animate 的属性对象将为 {left: 20, width: 100, top: 10}

这只是使用其他答案建议的必需的 [] 符号,但代码行数更少!


6
在变量周围加上方括号对我来说很有效。试试这个:
var thetop = 'top';
<something>.stop().animate(
    { [thetop] : 10 }, 10
);

这在旧版本的EcmaScript中不起作用,但现在这是一种非常干净的方法。 - Oliver

5
您也可以尝试像这样做:

const arr = [{
    "description": "THURSDAY",
    "count": "1",
    "date": "2019-12-05"
},
{
    "description": "WEDNESDAY",
    "count": "0",
    "date": "2019-12-04"
}]
const res = arr.map(value => {
    return { [value.description]: { count: value.count, date: value.date } }
})
console.log(res);


这对我帮助很大。谢谢 :) - jpisty

4

我找不到一份关于ES6和ES5之间区别的简单示例,因此我制作了一个。两个代码示例都创建完全相同的对象。但是ES5示例也适用于旧版浏览器(如IE11),而ES6示例则不适用。

ES6

我无法找到一个简单的例子来说明 ES6 和 ES5 之间的区别,因此我自己编写了一个样本。这两个代码示例创建完全相同的对象。但是,ES5 示例还可以在老版本浏览器中(如 IE11)运行,而 ES6 示例则不行。
var matrix = {};
var a = 'one';
var b = 'two';
var c = 'three';
var d = 'four';

matrix[a] = {[b]: {[c]: d}};

ES5

var matrix = {};
var a = 'one';
var b = 'two';
var c = 'three';
var d = 'four';

function addObj(obj, key, value) {
  obj[key] = value;
  return obj;
}

matrix[a] = addObj({}, b, addObj({}, c, d));

4
更新: 正如评论者指出的那样,任何支持箭头函数的JavaScript版本都将同时支持({[myKey]:myValue}),因此这个答案没有真正的用例(事实上,在一些奇怪的边缘情况下它可能会崩溃)。

不要使用下面列出的方法。


简直不能相信还没有人发帖:只需使用具有匿名评估的箭头函数即可!

完全无侵入性,不会干扰命名空间,只需要一行:

myNewObj = ((k,v)=>{o={};o[k]=v;return o;})(myKey,myValue);

演示:

var myKey="valueof_myKey";
var myValue="valueof_myValue";
var myNewObj = ((k,v)=>{o={};o[k]=v;return o;})(myKey,myValue);
console.log(myNewObj);

如果环境不支持新的{[myKey]: myValue}语法,比如——显然;我刚在我的网络开发者控制台上验证过——Firefox 72.0.1,发布于2020-01-08,那么下面这个方法就非常有用了。 我纠正一下,只要把这个东西括起来就可以了。

(我相信你可能会通过巧妙使用reduce等更强大/可扩展的解决方案或其他方式,但到了那个时候,你最好将对象创建拆分成自己的函数,而不是强行将其全部内联)


虽然问这个问题的人已经十年前了,并且并不重要,但为了完整起见并展示它如何确切地回答所述问题,我将在原始上下文中展示此内容:

var thetop = 'top';
<something>.stop().animate(
    ((k,v)=>{o={};o[k]=v;return o;})(thetop,10), 10
);

3
箭头函数和计算属性名同时引入。您的控制台检查不正确,因为您需要在控制台中键入({[myKey]: myValue})以使其成为对象,而不是块状内容(请参见https://dev59.com/9G865IYBdhLWcg3wnPya)。“只需要一行代码”——当然,整个压缩后的jQuery库也只需要一行代码。“非侵入式”的说法是不正确的,如果对象具有getter、setter或作为代理目标,则不是这样。 - Sebastian Simon
答案可以重写为 var myNewObj = (function (myKey, myValue) { o = {}; o[myKey] = myValue; return o; })(myKey, myValue); 以支持 ES6 以下的版本。 - Ramil Shavaleev

2
给定代码:
var thetop = 'top';
<something>.stop().animate(
    { thetop : 10 }, 10
);

翻译:

var thetop = 'top';
var config = { thetop : 10 }; // config.thetop = 10
<something>.stop().animate(config, 10);

正如您所看到的,{ thetop : 10 }声明并没有使用变量thetop。相反,它创建了一个名为thetop的键的对象。如果您希望键是变量thetop的值,则必须在thetop周围使用方括号:

var thetop = 'top';
var config = { [thetop] : 10 }; // config.top = 10
<something>.stop().animate(config, 10);

方括号语法是在ES6中引入的。在早期版本的JavaScript中,您需要执行以下操作:

var thetop = 'top';
var config = (
  obj = {},
  obj['' + thetop] = 10,
  obj
); // config.top = 10
<something>.stop().animate(config, 10);

obj['' + thetop] 可以直接替换为 obj[thetop]。它会自动转换为字符串,除非它是一个符号。 - Sebastian Simon

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