模板字符串作为对象属性名

119

为什么 JavaScript 不允许使用模板字符串作为对象属性的键?例如,当我输入:

foo = {`bar`: 'baz'}

当进入NodeJS REPL时,它会抛出一个带有“Unexpected template string”和长的堆栈跟踪的SyntaxError。然而,属性值是正常的,这并不意外。类似的错误也会在浏览器中发生,例如Firebug会抛出一个带有“invalid property id”的SyntaxError

模板字符串在“计算属性名”中是允许的。例如,这在支持该语法的所有浏览器中都可以完美编译:

var foo = {
    [`bar` + 1]: `baz`
};

并创建对象{"bar1": "baz"}

为什么模板字符串不能作为字面量对象的键?这是出于性能原因吗?模板字符串必须编译,可能在运行时(如果我理解不正确,请纠正我),这意味着每次遇到此对象时,解释器都必须计算对象名称。考虑到诸如“处理过的”模板字符串之类的事情,这似乎可能会变慢,尽管自ES5以来我们已经拥有了getter和setter。Firefox没有将其视为错误,这就是我觉得出乎意料的原因。这种语法将来是否允许?


2
这不就是为什么引入了计算属性名称的原因吗?是的,你需要在它周围加上花括号,但从语法上看,它似乎也更好地解决了各种场景的通用问题。 - Praveen Puglia
我正在重新思考我的答案,不太确定它是否正确。现在我正在查阅ES6文档... - Max
为什么模板字符串不能作为字面对象键?实际上是可以的,只是您的语法有误吗? - Evan Davis
@bergi的评论或者@nati Kamusher的回答应该被接受。@bergi简洁明了且正确,获得了97个赞。 "...你需要使用计算属性。可以使用var obj = {[`${dyanmicKey}`]: val}或者var obj = {[dyanmicKey]: val}。- Bergi于2016年5月31日14:14发表。 - Michael Wegter
3个回答

89
为什么模板字符串不允许作为字面对象键?
模板字符串是表达式而不是字面量1。您只能使用字符串字面量(和标识符)作为属性名称,对于其他所有内容(即不知道是否为静态值),您需要使用计算属性名称。
这并非出于性能原因,而是为了简化解析,并使常量(静态已知的)属性名称与动态计算的属性名称区分开来。
大多数情况下,这是一个没有人需要的功能。它不会简化或缩短任何东西,而且你可以通过其他方式实现相同效果。
这个语法将来会被允许吗?
不,不可能。 1: 即使它们被称为“模板字面量”,从技术上讲它们也不是字面量。并且: 模板甚至不需要是字符串,它们可以求值为任何内容。

3
这句话的意思是:如何处理以下代码中的动态变量和值赋予对象的情况:var obj = {`${dyanmicKey}` : val }。 - b4d4r
102
不行,你需要使用计算属性。可以使用以下方式之一:var obj = {[`${dyanmicKey}`]: val} 或只需 var obj = {[dyanmicKey]: val} - Bergi
1
哎呀,为什么不行呢。他们只是不想让人们在那里放表达式吧... - geoyws
1
@Bergi 哎呀,它把眯眼注释都拿走了,再看看这里的\profile.preferences.networks[${network.name}]\ - basickarl
1
这是什么意思:“模板甚至不需要是字符串,它们可以评估为任何东西”? - adiga
显示剩余7条评论

27

对象键应该是字符串:

let obj1 = { name: "Alex", age: "28"} // this is a 'normal' style

如果提供的键表达式不是字符串,则引擎将尝试将其强制转换为字符串。

let obj2 = { 5: "Banana", 10: "Apple" } // e.g. number key is coersed into string

模板字符串需要先进行求值,因此不能被“强制转换”,因此引擎会抛出错误,因为它试图强制转换它们(示例1)。

另一方面,数组天生可以被强制转换为字符串,因此可以用作完全合法的键。

此外,包含模板字符串的数组在创建对象时可以用作完全合法的键,因为引擎首先评估模板表达式,然后将数组强制转换为字符串(示例2)。

请参见以下示例:

    /* example 1 */ {`foo`: "bar"}   // Error: template strs aren't coersible

为了能够将模板字符串用作对象键,只需将其包装在数组的单个元素中:
    /* example 2 */ {[`foo`]: "bar"} /* OK: {foo: "bar"}, the internal `foo` 
                                           template is first resolved to a native 
                                           "foo" string, resulting in array ["foo"],
                                           which then coersed to the "foo" key.*/
    
    /* example 3 */ const obj = {foo: "bar"}
                        const obj1 = {[obj.foo]: "bar"} // OK: {bar: "bar"} !!

2
太有趣了。我从来没有想过为什么数组可以作为对象键名,但现在完全明白了! - trysis

7

我发表这个答案是为了将@Bergi非常受欢迎的评论提升为一个答案。如果你想在对象字面量中使用变量的动态值作为对象键,只需使用计算属性:

const dynamicKey = someCondition ? 'someKeyName' : 'otherKeyName';
const obj = {[dynamicKey]: val};

你也可以这样写:

const obj = {[`${dynamicKey}`]: val};

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