在ES6中,属性可以定义为符号属性:
var symbol = Symbol();
var object = {};
object[symbol] = 'value';
MDN将可枚举属性定义为可以通过for..in循环迭代的属性。 (1)。符号属性永远不会被for ... in循环迭代,因此它们可以被认为是不可枚举的(2)。
那么,你能做到这一点是否有意义:
Object.defineProperty(object, symbol, {
value: 'value',
enumerable: true
});
并且查询对象的描述符确实确认了这个属性是可枚举的:
Object.getOwnPropertyDescriptor(object, symbol)
// -> { enumerable: true }
为什么呢?这有什么用?
(1)https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties
(2)for ... in use [[Enumerate]]
,仅包含字符串键。由于我们有符号属性,因此可能应该更改MDN上的定义。
答案 0 :(得分:17)
是的,允许Symbol
属性可以枚举的原因是:Object.assign
:
let s1 = Symbol();
let s2 = Symbol();
let s3 = Symbol();
let original = {};
original[s1] = "value1"; // Enumerable
Object.defineProperty(original, s2, { // Enumerable
enumerable: true,
value: "value2"
});
Object.defineProperty(original, s3, { // Non-enumerable
value: "value3"
});
let copy = {};
Object.assign(copy, original);
console.log("copy[s1] is " + copy[s1]); // value1, because it was enumerable
console.log("copy[s2] is " + copy[s2]); // value2, because it was enumerable
console.log("copy[s3] is " + copy[s3]); // undefined, because it wasn't enumerable
关于Babel的REPL的
为了清楚起见:
MDN将可枚举属性定义为可以通过for..in循环迭代的属性。 (1)。
ES6(ES2015)的错误。在ES5及更早版本中,这是一个合理的,如果简单化的定义,由于Symbol
s,它不再是简单的正确定义。我修好了这篇文章。
这是一个CW,因为这是对这个问题的评论的产物。
答案 1 :(得分:5)
这是因为枚举规则包括需要字符串键的子句。请记住,枚举和要求键是不同的操作,具有完全不同的规则。
查看the section for for ... in
/for ... of
head evaluation (13.7.5.12),它表明迭代是使用:
- 醇>
如果iterationKind是枚举,那么
℃。返回
obj.[[Enumerate]]()
。
The description of [[Enumerate]]
(9.1.11)非常清楚地说明:
返回一个Iterator对象(25.1.1.2),其
next
方法迭代O
的可枚举属性的所有字符串值键。
对可枚举属性的检查稍后会出现在正文中,伪代码示例会使这一点更加清晰:
function* enumerate(obj) { let visited=new Set; for (let key of Reflect.ownKeys(obj)) { if (typeof key === "string") { // type check happens first let desc = Reflect.getOwnPropertyDescriptor(obj,key); if (desc) { visited.add(key); if (desc.enumerable) yield key; // enumerable check later } } } ... }
(评论我的)
显然,不会枚举具有非字符串键的属性。使用这个例子:
var symbol = Symbol();
var object = {};
Object.defineProperty(object, symbol, {
value: 'value',
enumerable: true
});
Object.defineProperty(object, 'foo', {
value: 'bar',
enumerable: true
});
Object.defineProperty(object, 'bar', {
value: 'baz',
enumerable: false
});
Object.defineProperty(object, () => {}, {
value: 'bin',
enumerable: true
});
for (let f in object) {
console.log(f, '=', object[f]);
}
for (let k of Object.getOwnPropertyNames(object)) {
console.log(k);
}
您可以在Babel和Traceur中验证。
但是,您会看到两件有趣的事情:
getOwnPropertyNames
包含不可枚举的属性。这是有道理的,如it follows completely different rules。for...in
包含两个转发器下的非字符串属性。这似乎与规范不符,但确实符合ES5的行为。