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-inObject.keysObject.getOwnPropertyNames 都只看字符串键控的属性。 ES2015 添加了Reflect.ownKeys(包括字符串和符号)和Object.getOwnPropertySymbols(仅包括自己的符号键属性)。


旁注:

似乎对于某些对象 d 它计算 s = d.toString() 并使用该值 s 作为属性键...

不仅仅是对象,它更像是String(d)(尽管如果d 是一个对象,它会涉及到同样的事情)。任何不是字符串或符号的东西都被转换为字符串。

...但是对于其他对象 d(例如,当 d 是 Symbol 时)它实际上使用 Symbol 的值作为键。

符号不是对象,符号是原始类型。但是是的,如果属性键是 Symbol,则直接使用它,而不是转换为字符串。

【讨论】:

再次感谢... 2个旁注也很有用。

以上是关于JavaScript - 计算属性 - 深深的困惑的主要内容,如果未能解决你的问题,请参考以下文章

Javascript:仍然对 instanceof 运算符感到困惑

如何创建将 1 添加到属性的 Ember 计算属性?

JavaScript 文本节点属性

困惑:我有 3 个空格(组合)和 3 个分类值。如何计算值的所有组合?

javascript 对象私有属性的行为就像是公共的

生物信息与数据挖掘培训 | 4月20日相聚中科院计算所