一。語法
創建語法:function* + yield
使用語法:next(returnValue).value/done
P.S.迭代器與生成器:function* 定義的東西叫迭代器的生成器(簡稱生成器),因為調用它返回一個迭代器
二。迭代器的作用
###1. 函數節流
把時耗多的複雜任務用 yield 分成小塊慢慢做,也叫函數柯里化 currying,更多信息請查看 JS 學習筆記 11_高級技巧
###2. 生成無限序列
比如斐波那契數列
###3. 方便遍歷
不用手動維護內部狀態
三。JavaScript 生成器實例
###1. 基本用法
function* fun(a) {
yield a + 1;
yield a * 2;
yield a * 2 + 1;
}
var iter = fun(3);
iter.next();
// => Object {value: 4, done: false}
iter.next();
// => Object {value: 6, done: false}
iter.next();
// => Object {value: 7, done: false}
function* fun(a) {
yield a=a + 1;
yield a=a * 2;
yield a=a * 2 + 1;
}
var iter = fun(3);
// => iter.next();
Object {value: 4, done: false}
iter.next();
// => Object {value: 8, done: false}
iter.next();
// => Object {value: 17, done: false}
iter.next();
// => Object {value: undefined, done: true}
函數執行遇到 yield,先 return yield 後面的值,再保存函數執行的 context(效果類似於保存斷點),下一次調用 next() 時,恢復 context,從 yield 的下一句開始執行,遇到 yield 或者 return 退出
###2. 高級用法
function* fib() {
var a = 1;
var b = 1;
while (true) {
var current = b;
b = a;
a = a + current;
var reset = yield current;
if (reset) {
a = 1;
b = 1;
}
}
}
var fibSeq = fib();
fibSeq.next();
// => Object {value: 1, done: false}
fibSeq.next();
// => Object {value: 1, done: false}
fibSeq.next();
// => Object {value: 2, done: false}
fibSeq.next();
// => Object {value: 3, done: false}
fibSeq.next();
// => Object {value: 5, done: false}
fibSeq.next(false);
// => Object {value: 8, done: false}
fibSeq.next(true);
// => Object {value: 1, done: false}
fibSeq.next(false);
// => Object {value: 1, done: false}
fibSeq.next(false);
// => Object {value: 2, done: false}
next() 可以接受參數,此參數會被當做 yield 的返回值傳回函數,這樣就可以控制函數內部的狀態,例如上面的是否 reset
###3. 比較繞的例子
function* fun(a) {
a = yield a + 1;
a = yield a * 2;
yield a * 2 + 1;
}
var iter = fun(3);
iter.next(0);
// => Object {value: 4, done: false}
iter.next(0);
// => Object {value: 0, done: false}
iter.next(1);
// => Object {value: 3, done: false}
類似的:
function* fun(a) {
a = yield a = a + 1;
a = yield a = a * 2;
yield a = a * 2 + 1;
}
var iter = fun(3);
iter.next(0);
// => Object {value: 4, done: false}
iter.next(0);
// => Object {value: 0, done: false}
iter.next(1);
// => Object {value: 3, done: false}
內部執行機制一樣,只是寫法比較繞
###4. 其它
此外,迭代器還有 throw() 和 return() 方法,FF 都實現了,Chrome 只實現了前者,更多信息請查看 MDN Iterators and generators
還有利用 1 個迭代器生成另一個迭代器的語法,例如:
function* fun() {
yield 1;
yield 2;
}
var iter = fun();
var newIter = (for (i of iter) i * 2);
newIter.next();
// => Object { value: 2, done: false }
newIter.next();
// => Object { value: 4, done: false }
注意,MDN 的例子有誤,必須是 for...of,且必須是圓括號(例子中的 for...in 和方括號都是錯的)
FF 支持這種語法,Chrome 不支持
三。相關語法
###1.for...of、for...in、forEach
for...of 用來遍歷屬性值,for...in 用來遍歷屬性名,forEach 是 Array.prototype 上的方法,能同時遍歷屬性名和屬性值
此外,for...of 也能遍歷 DOM NodeList 和自定義的迭代器(function* + yield),是 ES6 的新東西
實例如下:
var arr = [3, 5, 7];
arr.foo = "hello";
for (var i in arr) {
console.log(i); // logs "0", "1", "2", "foo"
}
for (var i of arr) {
console.log(i); // logs "3", "5", "7"
}
let arr = [3, 5, 7];
arr.foo = "hello";
arr.forEach(function (element, index) {
console.log(element); // logs "3", "5", "7"
console.log(index); // logs "0", "1", "2"
});
###2.yield*
與 yield 功能類似,也是用來遍歷的,但 yield* 後面跟迭代器對象,作用是進入後面的迭代器,遍歷完再回來,例如:
function* g1() {
yield 2;
yield 3;
yield 4;
}
function* g2() {
yield 1;
yield* g1();
yield 5;
}
var iterator = g2();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: 4, done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
有了 yield* 後,迭代器可以嵌套了,可以「線性」遍歷層級結構(當然,前提是拿到所有下層結構的迭代器對象)
暫無評論,快來發表你的看法吧