JavaScript - 计算属性 - 深深的困惑
Posted
技术标签:
【中文标题】JavaScript - 计算属性 - 深深的困惑【英文标题】:JavaScript - Computed properties - deep confusion 【发布时间】:2020-04-13 15:24:56 【问题描述】:似乎我对 javascript 中的计算属性感到很困惑。
当我定义一个对象并将[d]
作为一个键(作为属性键/名称)时,这个[d]
实际上做了什么?似乎对于某些值 d
它计算 s = d.toString()
并使用该值 s
作为属性键。
但是对于其他值 d
(例如,当 d
是符号时)它实际上使用符号的值作为键。
所以[d]
(作为语法结构)的这种双重行为似乎令人困惑。有人可以深入解释这是如何工作的吗?
顺便说一句,还有其他特殊情况吗?或者只是当d
是一个符号时我们有这种特殊行为?
回到基础:什么事物可以是对象属性的键/名称?它只是字符串还是字符串和符号,或者还有其他东西......?
例子:
var symbol = Symbol("test");
function Animal(name)
this.name = name;
Animal.prototype = ;
Animal.prototype.constructor = Animal;
function Dog(breed)
this.breed = breed;
this.name = "Dog";
this.s = symbol;
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
console.log("001");
var d = new Dog("Sharo");
for (let x in d)
console.log(x, ":", d[x]);
console.log("002");
d = new Object();
for (let x in d)
console.log(x, ":", d[x]);
console.log("003");
d = new Number(5);
for (let x in d)
console.log(x, ":", d[x]);
var d1 = ;
var d2 = ;
var d = new Dog("Sharo");
var m = [d1] : 5, [d2] : 10, [d] : 20, z : 100, symbol: 2000, [symbol] : 5000;
console.log("============================");
console.log(m);
for (let x in m)
console.log(x, ":", m[x]);
console.log("============================");
【问题讨论】:
你读过例如developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…? “属性名称是字符串或符号。任何其他值,包括数字,都被强制转换为字符串。” @jonrsharpe 不,我没有...只有书籍(其中一些 15 年前根本没有符号)...其中一些(即使是最近的)考虑了这一点信息太基本,直接跳过提及Symbol
。他们只是谈论属性名称,很自然地假设名称是字符串和字符串。这就是造成我困惑的原因。这个链接似乎正是我需要的!谢谢。
@Victor - 这就是 devtools 向您展示的方式,因为您可以在对象文字中使用数字文字作为键名 - 但生成的属性键是一个字符串。试试这个:for (const key in 1:1) console.log(`$key: $typeof key`);
(同样,请参阅下面的答案,这些答案是指规范的相关部分。)
@T.J.Crowder 哇!你是对的......感谢您花时间(和耐心)指出这一点。顺便说一句:我之前赞成你的答案(目前,唯一的一个......绝对值得更多赞成)imgbbb.com/image/L4PIlH
@Victor - 我的荣幸。 :-) 如果您对添加到 JavaScript 中的新内容感兴趣,我将在明年初出版一本书——我的个人资料中的链接。 :-) 编码愉快!
【参考方案1】:
由于似乎没有人有兴趣回答这个问题,我将根据上面得到的 cmets 自己回答,因此我不再感到困惑。
请注意,这里的答案是基于 ES6 的。我的意思是...谁知道 JavaScript 的未来还会有什么 :)
当我定义一个对象并将
[d]
作为一个键(作为属性键/名称)时,这个[d]
实际上做了什么?似乎对于某些对象d
它计算s = d.toString()
并使用该值s
作为属性键。但是对于其他对象d
(例如,当d
是符号时)它实际上使用符号的值作为键。
是的,没错。当 d 是 Symbol 时,直接使用它的值。当 d 不是 Symbol 时,它的值被强制转换为字符串,并且该字符串用作属性名称/键。强制更像String(d)
而不是d.toString()
。
所以
[d]
(作为语法结构)的这种双重行为似乎令人困惑。有人可以深入解释这是如何工作的吗?
上面已经解释过了。
顺便说一句,还有其他特殊情况吗?或者只是当
d
是一个符号时我们有这种特殊行为?
没有其他“特殊情况”。从 ES6 开始,只有字符串和符号可以作为属性键。
回到基础:什么事物可以是对象属性的键/名称?它只是字符串还是字符串和符号,或者还有其他一些东西......?
如前所述,从 ES6 开始,只有字符串和符号可以作为属性键。
参考资料:
(1) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors
“属性名称是字符串或符号。任何其他值,包括数字,都被强制转换为字符串。”
(2) https://www.ecma-international.org/ecma-262/6.0/#sec-topropertykey
【讨论】:
@Andreas 好主意。完成。 函数作为键怎么样?const m = new Map(); const p = (x) => console.log(x); m.set(p, "test"); for ([key, value] of m) key(value); key(1);
【参考方案2】:
在对另一个答案的评论中,您说您认为属性键始终是字符串。他们是,直到 ES2015。 :-)
所以
[d]
(作为语法结构)的这种双重行为似乎令人困惑。有人可以深入解释一下这是如何工作的吗?
从 ES2015 开始,语言中添加了符号,对象属性键可以是字符串或符号。所以当你这样做时:
const obj =
[d]: "foo"
;
...计算的属性键 ([d]: "foo"
) 部分的工作方式如下:
-
让
value
是表达式"foo"
的计算结果
让keyValue
是表达式d
的计算结果
如果keyValue
是一个符号,让key
= keyValue
;否则,让key
= String(keyValue)
将obj
上的属性key
设置为值value
为了清楚起见,我在其中省略了一些细节。您可以在规范中的 ToPropertyKey 抽象操作中看到这一点,每当将值用作属性键时(在上面的对象文字中,或通过括号表示法访问对象属性等)时,都会使用该操作。
顺便说一句,还有其他特殊情况吗?或者只是当我们有这种特殊行为时 d 是一个符号?
回到基础:什么东西可以是对象属性的键/名称?它只是字符串还是字符串和符号,或者还有其他一些东西......?
只是符号和字符串。 :-) Symbol 并不是一个特例,只是以前属性键总是字符串,现在它们可以是字符串或符号.
(有趣的事实:在规范中,they define“property key”作为标识属性的字符串或符号,而“property name”作为属性键,它是一个字符串。但不要依赖它,规范本身有点不一致,Object.keys
方法——它返回属性 names 的数组,而不是属性 keys——在 ES2015 中添加该术语之前就已经存在。然后他们向数组添加了一个 keys
方法,该方法返回 numbers [数组中的 indexes] 的迭代器。有趣有趣... :-) )
在 ES2015 中指定了所有返回或循环属性名称的 ES5 和更早的操作以忽略符号键属性。所以for-in
、Object.keys
、Object.getOwnPropertyNames
都只看字符串键控的属性。 ES2015 添加了Reflect.ownKeys
(包括字符串和符号)和Object.getOwnPropertySymbols
(仅包括自己的符号键属性)。
旁注:
似乎对于某些对象 d 它计算 s = d.toString() 并使用该值 s 作为属性键...
不仅仅是对象,它更像是String(d)
(尽管如果d
是一个对象,它会涉及到同样的事情)。任何不是字符串或符号的东西都被转换为字符串。
...但是对于其他对象 d(例如,当 d 是 Symbol 时)它实际上使用 Symbol 的值作为键。
符号不是对象,符号是原始类型。但是是的,如果属性键是 Symbol,则直接使用它,而不是转换为字符串。
【讨论】:
再次感谢... 2个旁注也很有用。以上是关于JavaScript - 计算属性 - 深深的困惑的主要内容,如果未能解决你的问题,请参考以下文章
Javascript:仍然对 instanceof 运算符感到困惑