迭代器
1:是一个 iterable,它产生的迭代器可以消耗其自身值
一些内置类型拥有默认的迭代器行为,其他类型(如 Object
)则没有。下表中的内置类型拥有默认的@@iterator
方法:
Array.prototype[@@iterator]()
TypedArray.prototype[@@iterator]()
String.prototype[@@iterator]()
Map.prototype[@@iterator]()
Set.prototype[@@iterator]()
快速转换的方法是 Symbol.iterator
var arr = [1,2,3];
var it = arr[Symbol.iterator]();
it.next(); // { value: 1, done: false }
it.next(); // { value: 2, done: false }
it.next(); // { value: 3, done: false }
it.next(); // { value: undefined, done: true }
生成器
function *foo() {
// ..
}
function *foo() {
var x = yield 2;
z++;
var y = yield (x * z);
console.log( x, y, z );
}
var z = 1;
var it1 = foo();
var it2 = foo();
var val1 = it1.next().value; // 2 <-- yield 2
var val2 = it2.next().value; // 2 <-- yield 2
val1 = it1.next( val2 * 10 ).value; // 40 <-- x:20, z:2
val2 = it2.next( val1 * 5 ).value; // 600 <-- x:200, z:3
it1.next( val2 / 2 ); // y:300
// 20 300 3
it2.next( val1 / 4 ); // y:10
// 200 10 3
(1) *foo() 的两个实例同时启动,两个 next() 分别从 yield 2 语句得到值 2。
(2)
val2 * 10
也就是
2 * 10
,发送到第一个生成器实例
it1
,因此
x
得到值
20
。
z
从
1
增
加到
2
,然后
20 * 2
通过
yield
发出,将
val1
设置为
40
。
(3)
val1 * 5
也就是
40 * 5
,发送到第二个生成器实例
it2
,因此
x
得到值
200
。
z
再次从
2
递增到
3
,然后
200 * 3
通过
yield
发出,将
val2
设置为
600
。
(4)
val2 / 2
也就是
600 / 2
,发送到第一个生成器实例
it1
,因此
y
得到值
300
,然后打印
出
x y z
的值分别是
20 300 3
。
(5)
val1 / 4
也就是
40 / 4
,发送到第二个生成器实例
it2
,因此
y
得到值
10
,然后打印出
x y z
的值分别为
200 10 3
。
function *foo() {
yield;
console.log(2)
}
var it = foo();
it.next() // {value: undefined, done: false}
it.next() // 2
{value: undefined, done: true}
function *foo(x) {
if (x < 3) {
x = yield *foo( x + 1 );
}
return x * 2;
}
foo( 1 );
foo(1) 以及之后的调用迭代器的 next() 来运行递归步骤的结果是 24。第一个 *foo(..) 运 行 x 值为 1,满足 x < 3。x + 1 被递归地传给 *foo(..),所以这一次 x 为 2。再次的递归 调用使得 x 值为 3。
现在,因为不满足 x < 3,递归停止,返回 3 * 2 也就是 6 给前一个调用的 yield *.. 表达 式,这个值被赋给 x。再次返回 6 * 2 的结果 12 给前一次调用的 x。最后是 12 * 2,也就 是 24,返回给 *foo() 生成器的完成结果。
技巧:
可以看出,整个生成器 迭代完成 next 比 yield 多一次,第一次next可以理解为启动
yield 可以看作是 return, 是对应 next().value 的输出值;
next(val) 给 yield作出返回值