Javascript 可迭代对象的技术定义是什么?您如何测试它?

What is the technical definition of a Javascript iterable and how do you test for it?

我一直在实现 ES6 Set 对象的一个​​有用的子类。对于我的许多新方法,我想接受一个参数,它可以是另一个 Set 或 Array,或者任何我可以迭代的东西。我一直在我的界面中调用 "iterable" 并在其上使用 .forEach() (这适用于集合或数组。示例代码:

// remove items in this set that are in the otherIterable
// returns a count of number of items removed
remove(otherIterable) {
    let cnt = 0;
    otherIterable.forEach(item => {
        if (this.delete(item)) {
            ++cnt;
        }
    });
    return cnt;
}

// add all items from some other iterable to this set
addTo(iterable) {
    iterable.forEach(item => {
        this.add(item);
    });
}

但是,我怀疑我可能并没有真正支持 ES6 定义它的方式的任何可迭代对象,所以我对 Javascript 可迭代对象的真正定义是使用 ES6 规范中的术语感兴趣做?

你如何在 ES6 中测试它 Javascript?

你应该如何迭代一个通用的可迭代对象?

我在 ES6 规范中发现了这样的短语:

If the parameter iterable is present, it is expected to be an object that implements an @@iterator method that returns an iterator object that produces a two element array-like object whose first element is a value that will be used as a WeakMap key and whose second element is the value to associate with that key.

但是,那指的是一个 @@iterator method,我似乎无法通过那个 属性 名称访问它。

在 Symbol 构造函数上有一个特殊的 属性,Symbol.iterator,它的值是,呃,我猜你会说 "conceptual" 属性 name "@ @迭代器”。所以你可以像这样为一个对象创建一个迭代器方法:

object[Symbol.iterator] = function* () {
  // do something that makes sense
};

你也可以通过

来测试某个对象是否是一个迭代器
if (Symbol.iterator in object)

(也许还会检查它是否是一个函数)。现在那些迭代器函数(Symbol.iterator 属性 的值)是 generator 函数(不是我编辑到示例中的 * )。因此,您可以通过首先调用函数并保存返回的对象,然后调用 .next() 来启动它们并获取值。这将为您提供一个具有 valuedone 属性的对象。

您也可以让 for ... of 或 "spread" ... 运算符处理迭代器函数。

What is the real definition of a Javascript iterable using the term as the ES6 specification does?

§25.1.1.1 定义 "The Iterable Interface".

它们是具有 Symbol.iterator 键控方法的对象,该方法 returns 是一个有效的 Iterator (这反过来又是一个预期行为的对象应该根据 §25.1.1.2).

How do you test for it in ES6 Javascript?

我们无法在不调用的情况下测试@@iterator方法returns的内容,在不尝试运行它的情况下我们无法测试结果是否符合Iterator接口.最好的选择是做

function looksIterable(o) {
    return typeof o[Symbol.iterator] == "function";
}

但是我通常不会对此进行测试,而是在它不可迭代时让它失败并引发异常。

How should you iterate a generic iterable?

不要使用forEach.(事实上,在 ES6 的任何地方都不要使用 forEach)。

迭代的正确方法是 for (… of …) 循环。它对可迭代性进行所有检查(使用抽象 GetIterator operation 和 运行 宁(甚至关闭)迭代器,并在用于不可迭代值时抛出适当的 TypeErrors。