这是因为枚举规则包括要求字符串键的条款。请记住,枚举和请求键是完全不同的操作,具有完全不同的规则。
查看
“for ... in”/“for ... of”头部评估(13.7.5.12)的部分,它指出迭代使用以下方式完成:
如果iterationKind是enumerate,则
c. 返回obj.[[Enumerate]]()
。
[[Enumerate]]
的描述(9.1.11)非常清楚地说明了它:
返回一个迭代器对象(25.1.1.2),其
next
方法遍历
O
的所有可枚举属性的字符串键。枚举属性的检查稍后在函数体中进行,伪代码示例更加清晰明了。
function* enumerate(obj) {
let visited=new Set;
for (let key of Reflect.ownKeys(obj)) {
if (typeof key === "string") {
let desc = Reflect.getOwnPropertyDescriptor(obj,key);
if (desc) {
visited.add(key);
if (desc.enumerable) yield key;
}
}
}
...
}
显然,具有非字符串键的属性将不会被枚举。使用这个例子:
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
包括不可枚举属性。这很有道理,因为 它遵循完全不同的规则。
for...in
在两个转换器下都包括非字符串属性。这似乎不符合规范,但与ES5的行为相匹配。
[[Enumerate]]
只列出字符串属性,而不是所有可枚举属性? - loganfsmyth[[OwnPropertyKeys]]
也会返回符号。Object.assign
只是查看可枚举标志,无论该值是普通键还是符号。所以,是的,由于符号的enumerable
标志默认也为true
,它们被复制了。似乎它们只在for/in/of
循环中受到特殊处理。 - Felix Kling