你能在JavaScript中使属性可枚举但不可迭代吗?

6

我想知道是否有一种方法可以使对象属性像在for in循环中一样可枚举,但不会出现在for of loop中。

Object.defineProperty({},'prop',{
    enumerable:true,
    iterable:false
}

如果没有,是否有计划实现这样的功能?或者for of循环是否使用可枚举属性?


我已经谷歌过了,但没有发现任何暗示会有一个具体名称的属性。我只是想知道是否有计划实现一种方法使值可迭代而键不可枚举,我会更新我的问题以使问题更加清晰明了。 - Jim Jones
1
如果您正在寻求编程方面的帮助,那么您可能在错误的地方提问。在ES6邮件列表上提问更有可能得到您想要的答案。Stackoverflow主要是关于提出代码问题并获得代码答案的。 - Mike 'Pomax' Kamermans
5
@Mike'Pomax'Kamermans,不需要这么粗鲁。撇开态度不谈,这个问题并没有离题。当C++11正在形成时,我们看到了大量类似的问题。 - Chris Hayes
2个回答

5

我在Mozilla开发者网络(MDN)上进行了一些调查。

事实证明,对象有一个obj.propertyIsEnumerable(prop)方法来检查属性是否可枚举。从MDN中给出的示例来看,通过原型链继承的属性是不可枚举的,因此对于这些属性,该方法返回false。

非可枚举属性的一个例子是构造函数和数组的length属性。

至于问题中提到的可迭代部分,我将引用MDN的说法:“ECMAScript 6中的可迭代是一个接口(或者换句话说,协议),而不是像数组或映射这样的对象类型”。

也就是说,对象需要实现此接口才能使其属性可迭代。内置可迭代对象(如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循环中显示为可枚举。对于可迭代对象,您需要一个实现,可以使用之前提到的实现或者自己编写。这里有一个来自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循环中显示其属性。

2
for infor of循环的区别在于,一个使用obj.[[enumerate]],另一个使用GetIterator(obj)来确定循环的项。[[enumerate]](除非obj是代理对象)

返回一个迭代器对象,其next方法遍历obj可枚举属性的所有字符串键。

GetIterator会(尝试)调用@@iterate方法 - 但是,普通对象不实现此接口。因此,除非您明确声明,否则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;
}
< p > (未经测试,但我希望您能理解我的意思)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接