4

对于实现可迭代接口的对象,它必须实现[Symbol.iterator]指向返回iterator. 我想知道for..of循环是否在内部调用对象上的此方法来获取它iterator

我很好奇的原因是,例如,Map定义了一个带有多个迭代器(条目、值、键)的接口,如果没有明确指定,for..of循环似乎使用map.entries()调用返回的迭代器。

我试图在规范中搜索,但它只指定iterator作为参数传递给抽象操作ForOf

使用参数 lhs、stmt、 iterator、iterationKind、lhsKind 和 labelSet调用抽象操作 ForIn/ OfBodyEvaluation。

所以基本上两个问题:

  1. 如何从对象中获取迭代器?
  2. 规范中在哪里指定?
4

2 回答 2

1

具体指定操作的地方在7.4.1 GetIterator(obj[,method])中。这将获取@@iterator步骤 1a 中传递的对象的属性。抽象操作:

一种。将方法设置为GetMethod ( obj , @@iterator)。

@@iterator是一个众所周知的符号,它是Symbol.iterator对象的属性。

由于13.7.5.11 运行时语义中的产生,这被 for-in 和 for-of 循​​环使用:

IterationStatement : for( ForDeclaration of AssignmentExpression )语句

  1. keyResult为执行ForIn/OfHeadEvaluation的结果(ForDeclaration 的BoundNamesAssignmentExpression,迭代)。
  2. 返回 ForIn/OfBodyEvaluation ( ForDeclaration , Statement , keyResult , iterate, lexicalBinding, labelSet )。

在这里,您可以看到传递给ForIn/OfBodyEvaluation的迭代器参数是ForIn / OfHeadEvaluation的返回值keyResult。在步骤 7b 中,返回值是:

湾。返回GetIterator ( exprValue )。

@@iterator因此,for-of 循​​环通过按规范访问orSymbol.iterator众所周知的符号来获取迭代器。

于 2017-10-10T11:41:04.860 回答
1

一个对象只能定义一个符号Symbol.iterator,该符号将在对象本身的迭代中被调用。对象的其他属性,例如您给出的示例 ( entries, keys, values) 也可能返回一个迭代器,但这些通常不是相同的迭代器。它们可能是相同的,但这只是一个实现选择。使用 迭代对象时,调用哪个迭代器没有歧义for..of。它是由 . 返回的那个[Symbol.iterator]

  1. 如何从对象中获取迭代器?

您可以通过调用以 为键的函数来获取它Symbol.iterator,例如

const iterator = obj[Symbol.iterator]();

它是用 隐式检索的for..of

  1. 规范中在哪里指定?

规格中的此表说明:

@@iterator "Symbol.iterator"

返回对象的默认迭代器的方法。由for-of语句的语义调用。

以下是如何创建自定义函数以返回对象的默认迭代器(覆盖默认迭代器),并查看它是如何被调用的:

const obj = {
    // Define a custom function for returning the default iterator for this object
    [Symbol.iterator]: function () {
        console.log('The iterator-returning function got invoked');
        // Return an iterator from some other object
        //  (but we could have created one from scratch as well):
        return 'abc'[Symbol.iterator]();
    },
    myMethod: function () {
        // This method happens to return the same iterator
        return this[Symbol.iterator]();
    },
    myOtherMethod: function () {
        // This method happens to return another iterator
        return 'def'[Symbol.iterator]();
    }
}

for (const a of obj) {
    console.log(a); // a b c
}
for (const a of obj.myMethod()) {
    console.log(a); // a b c
}
for (const a of obj.myOtherMethod()) {
    console.log(a); // d e f
}
.as-console-wrapper { max-height: 100% !important; top: 0; }

于 2017-10-10T11:49:32.447 回答