这篇翻译不完整。请帮忙从英语翻译这篇文章。
该新特性属于 ECMAScript 2015(ES6)规范,在使用时请注意浏览器兼容性。
迭代协议
"迭代" 协议
The "iterable" protocol allows JavaScript objects to define or customize their iteration behavior, such as what values are looped over in a for..of
construct. Some built-in types, such as Array
or Map
, have a default iteration behavior, while other types (such as Object
) do not.
In order to be iterable, an object must implement the @@iterator method, meaning that the object (or one of the objects up its prototype chain) must have a property with a Symbol
.iterator
key:
Property | Value |
---|---|
[Symbol.iterator] |
A zero arguments function that returns an object, conforming to the iterator protocol. |
Whenever an object needs to be iterated (such as at the beginning of a for..of
loop), its @@iterator
method is called with no arguments, and the returned iterator is used to obtain the values to be iterated.
The "iterator" protocol
The "iterator" protocol defines a standard way to produce a sequence of values (either finite or infinite).
An object is an iterator when it implements a next() method with the following semantics:
Property | Value |
---|---|
next |
A zero arguments function that returns an object with two properties:
|
Iterators are in turn iterables:
var someArray = [1, 5, 7]; var someArrayEntries = someArray.entries(); someArrayEntries.toString(); // "[object Array Iterator]" someArrayEntries === someArrayEntries[Symbol.iterator](); // true
使用迭代对象的实例
A String
is an example of a built-in iterable object:
var someString = "hi"; typeof someString[Symbol.iterator] // "function"
迭代字符串默认返回一个又一个的字符
var iterator = someString[Symbol.iterator](); iterator + "" // "[object String Iterator]" iterator.next() // { value: "h", done: false } iterator.next() // { value: "i", done: false } iterator.next() // { value: undefined, done: true }
Some built-in constructs, such as the spread operator, use the same iteration protocol under the hood:
[...someString] // ["h", "i"]
We can redefine the iteration behavior by supplying our own @@iterator
:
var someString = new String("hi"); // need to construct a String object explicitly to avoid auto-boxing someString[Symbol.iterator] = function() { return { // this is the iterator object, returning a single element, the string "bye" next: function() { if (this._first) { this._first = false; return { value: "bye", done: false }; } else { return { done: true }; } }, _first: true }; };
Notice how redefining @@iterator
affects the behavior of built-in constructs, that use the iteration protocol:
[...someString] // ["bye"] someString + "" // "hi"
创建迭代
String
, Array
, Map
, Set
and Generator
objects are all built-in iterables, because the prototype objects of them all have an @@
iterator
method.
The arguments
object is also a built-in iterable, but it has an own property @@iterator
, not a prototype one.
用户定义迭代对象
We can make our own iterables like this:
var myIterable = {} myIterable[Symbol.iterator] = function* () { yield 1; yield 2; yield 3; }; [...myIterable] // [1, 2, 3]
基于API建立迭代
Map([iterable])
, WeakMap([iterable])
, Set([iterable])
and WeakSet([iterable])
:
var myObj = {} new Map([[1,"a"],[2,"b"],[3,"c"]]).get(2) // "b" new WeakMap([[{},"a"],[myObj,"b"],[{},"c"]]).get(myObj) // "b" new Set([1, 2, 3]).has(3) // true new Set("123").has("2") // true new WeakSet(function*() { yield {}; yield myObj; yield {}; }()).has(myObj) // true
and Promise.all(iterable)
, Promise.race(iterable)
, Array.from()
Syntaxes need iterables
for-of, spread, yield*, destructing
for(let value of ["a", "b", "c"]){ console.log(value) } // "a" // "b" // "c" [..."abc"] // ["a", "b", "c"] function* gen(){ yield* ["a", "b", "c"] } gen().next() // { value:"a", done:false } [a, b, c] = new Set(["a", "b", "c"]) a // "a"
Non-well-formed iterables
If an iterable's @@iterator
method doesn't return an iterator object, then it's a non-well-formed iterable, using it as such is likely to result in runtime exceptions or buggy behavior:
var nonWellFormedIterable = {} nonWellFormedIterable[Symbol.iterator] = () => 1 [...nonWellFormedIterable] // TypeError: [] is not a function
A generator object is an iterator or an iterable?
The answer is, both are correct:
var aGeneratorObject = function*(){ yield 1; yield 2; yield 3; }() typeof aGeneratorObject.next // "function", because it has a next method, so it's an iterator typeof aGeneratorObject[Symbol.iterator] // "function", because it has an @@iterator method, so it's an iterable aGeneratorObject[Symbol.iterator]() === aGeneratorObject // true, because its @@iterator method return its self (an iterator), so it's an well-formed iterable [...aGeneratorObject] // [1, 2, 3]