`for..of` 循环如何从对象中解析迭代器?
How does `for..of` loop resolve the iterator from an object?
对于实现可迭代接口的对象,它必须实现指向 returns iterator
函数的 [Symbol.iterator]
键。我想知道 for..of
循环是否在内部调用对象上的此方法来获取 iterator
?
我很好奇的原因是,例如,Map
定义了一个带有多个迭代器(条目、值、键)的接口,而且如果没有明确指定,for..of
循环似乎使用 map.entries()
调用返回的迭代器。
我正在尝试搜索 in the specification 但它只指定 iterator
作为参数传递给抽象操作 ForOf
:
The abstract operation ForIn/OfBodyEvaluation is called with arguments
lhs, stmt, iterator, iterationKind, lhsKind, and labelSet.
所以基本上有两个问题:
- 如何从对象中获取迭代器?
- 规范中哪里规定的?
具体操作指定的地方在7.4.1 GetIterator( obj [ , method ] )。这将获取步骤 1a 中传递的对象的 @@iterator
属性。抽象操作:
a. Set method to GetMethod(obj, @@iterator).
@@iterator
是一个 well-known symbol 即对象上的 Symbol.iterator
属性。
由于 13.7.5.11 Runtime Semantics 中的产生式,for-in 和 for-of 循环使用了它:
IterationStatement : for(ForDeclaration of AssignmentExpression) Statement
- Let keyResult be the result of performing ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, AssignmentExpression, iterate).
- Return ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, iterate, lexicalBinding, labelSet).
在这里,您可以看到传递给 ForIn/OfBodyEvaluation is the return value keyResult of ForIn/OfHeadEvaluation 的迭代器参数。 return 值是,在步骤 7b 中:
b. Return GetIterator(exprValue).
因此,for-of 循环通过按规范访问 @@iterator
或 Symbol.iterator
众所周知的符号来获取迭代器。
一个对象只能定义一个符号Symbol.iterator
,即在对象自身上迭代时调用的符号。
对象的其他属性,比如你给出的例子(entries
、keys
、values
)也可能是return一个迭代器,但这些一般不是相同的迭代器。它们 可以 相同,但这只是一种实现选择。在用 for..of
迭代对象时,调用哪个迭代器是没有歧义的。它是由 [Symbol.iterator]
编辑的 return。
- How iterator is obtained from an object?
您可以通过调用Symbol.iterator
键控的函数来获取它,例如
const iterator = obj[Symbol.iterator]();
它是用 for..of
隐式检索的。
- Where is it specified in the spec?
@@iterator "Symbol.iterator"
A method that returns the default Iterator for an object. Called by the semantics of the for-of
statement.
下面是如何为对象的默认迭代器 return 创建自定义函数(覆盖默认迭代器),并查看它是如何被调用的:
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; }
对于实现可迭代接口的对象,它必须实现指向 returns iterator
函数的 [Symbol.iterator]
键。我想知道 for..of
循环是否在内部调用对象上的此方法来获取 iterator
?
我很好奇的原因是,例如,Map
定义了一个带有多个迭代器(条目、值、键)的接口,而且如果没有明确指定,for..of
循环似乎使用 map.entries()
调用返回的迭代器。
我正在尝试搜索 in the specification 但它只指定 iterator
作为参数传递给抽象操作 ForOf
:
The abstract operation ForIn/OfBodyEvaluation is called with arguments lhs, stmt, iterator, iterationKind, lhsKind, and labelSet.
所以基本上有两个问题:
- 如何从对象中获取迭代器?
- 规范中哪里规定的?
具体操作指定的地方在7.4.1 GetIterator( obj [ , method ] )。这将获取步骤 1a 中传递的对象的 @@iterator
属性。抽象操作:
a. Set method to GetMethod(obj, @@iterator).
@@iterator
是一个 well-known symbol 即对象上的 Symbol.iterator
属性。
由于 13.7.5.11 Runtime Semantics 中的产生式,for-in 和 for-of 循环使用了它:
IterationStatement : for(ForDeclaration of AssignmentExpression) Statement
- Let keyResult be the result of performing ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, AssignmentExpression, iterate).
- Return ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, iterate, lexicalBinding, labelSet).
在这里,您可以看到传递给 ForIn/OfBodyEvaluation is the return value keyResult of ForIn/OfHeadEvaluation 的迭代器参数。 return 值是,在步骤 7b 中:
b. Return GetIterator(exprValue).
因此,for-of 循环通过按规范访问 @@iterator
或 Symbol.iterator
众所周知的符号来获取迭代器。
一个对象只能定义一个符号Symbol.iterator
,即在对象自身上迭代时调用的符号。
对象的其他属性,比如你给出的例子(entries
、keys
、values
)也可能是return一个迭代器,但这些一般不是相同的迭代器。它们 可以 相同,但这只是一种实现选择。在用 for..of
迭代对象时,调用哪个迭代器是没有歧义的。它是由 [Symbol.iterator]
编辑的 return。
- How iterator is obtained from an object?
您可以通过调用Symbol.iterator
键控的函数来获取它,例如
const iterator = obj[Symbol.iterator]();
它是用 for..of
隐式检索的。
- Where is it specified in the spec?
@@iterator "Symbol.iterator"
A method that returns the default Iterator for an object. Called by the semantics of the
for-of
statement.
下面是如何为对象的默认迭代器 return 创建自定义函数(覆盖默认迭代器),并查看它是如何被调用的:
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; }