我只是想知道是否有办法让对象属性可以像for in
循环那样枚举,但不会出现在for of loop
类似
Object.defineProperty({},'prop',{
enumerable:true,
iterable:false
}
如果没有,有没有计划实现这样的功能?或者for of
循环是否使用可枚举属性
答案 0 :(得分:4)
我在Mozilla开发网络(MDN)上进行了一些挖掘。
原来,对象有一个obj.propertyIsEnumerable(prop)
方法来检查属性是否可枚举。根据MDN中给出的示例,通过原型链继承的属性不可枚举,因此该方法对这些属性返回false。
非可枚举属性的一个示例是构造函数和数组的属性length
。
对于问题的可迭代部分,我将引用MDN:“ECMAScript 6中的Iterable是一个接口(或者换句话说,一个协议),而不是像Array或Map这样的对象类型。”
也就是说,对象需要实现此接口以使其属性可迭代。这是内置迭代的情况,例如String,Array,Map,Set,WeakSet和Generator对象。
以下代码说明了这一点:
var aString = "hello"
typeof aString[Symbol.iterator] // "function"
aString[Symbol.iterator]() + "" // "[object String Iterator]"
[...aString] // ["h", "e", "l", "l", "o"]
当然,您可以定义自己的迭代器实现。
回到这个问题,附加到对象或其原型的属性(直接,意思不是通过继承)将在for...in
循环中显示为可枚举。对于iterables,您需要一个实现,或者前面提到的实现,或者您自己的实现。这是MDN的一个很好的例子。
let arr = [ 3, 5, 7 ];
arr.foo = "hello";
for (let i in arr) {
console.log(i); // logs "0", "1", "2", "foo" these are property names or indexes
}
for (let i of arr) {
console.log(i); // logs "3", "5", "7" these are actual values of an
// iterable implementation provided by the array prototype
}
let
关键字在此上下文中与var
定义相同(尽管它有更多含义,但它们超出了本文的范围)。
正如您所看到的,数组已经具有iterable
接口的实现(来自数组原型),因此它在使用for...of
循环时产生其值,而foo
不显示属性(既不是值也不是属性名称)。
因此,如果您的对象没有实现iterable
接口,则它不应该是可迭代的(原则上),因此它将在for...of
循环中显示其属性。
答案 1 :(得分:2)
for in
and for of
evaluations之间的区别在于,其中一个使用obj.[[enumerate]]
而另一个使用GetIterator(obj)
来确定循环项目。 [[enumerate]]
does(除非obj
是代理)
返回Iterator object,其
next
方法遍历obj
的可枚举属性的所有字符串值键。
GetIterator
将(尝试)调用@@iterate
method - 但是,普通对象不会实现此接口。
因此除非您明确说明,否则任何属性都不会出现在for of
循环中:
function defineIterableProperty(obj, prop, desc) {
let old = obj[Symbol.iterate];
Object.defineProperty(obj, prop, desc);
obj[Symbol.iterate] = function* () {
if (old) yield* old.call(this);
yield prop;
};
return obj;
}
(未经测试,但我希望你明白这一点)