ES6中的生成器和迭代器

生成器函數generator function 用function *name () {}來聲明,調用生成器函數則會返回一個生成器對象generator,並且符合可迭代協議和迭代器協議,因此generator也是一個迭代器對象,具有next()方法,調用next()方法會執行生成器函數內的語句(即遍歷生成器函數內部的狀態,狀態值由yield後的表達式值給出)。

function *foo ( x ) {
	yield 1;
	var y = x + ( yield 2 );
	var z = y + ( yield );
	return; 
}
var it = foo(3); // x = 3; 首次調用生成器函數返回一個對象,具有next()方法的迭代器對象;
it.next().value; // 1 ;調用next方法來遍歷狀態,在遇到yield語句時停下來,返回具有{value: value, done: false}形式的對象,其中value值是yield後的表達式值,done表示迭代是否結束;
it.next().value; // 2 第二次調用next方法,從上次yield停下來的地方繼續執行,注意上一次只執行yield及其表達式,如果yield表達式包含在語句中,則該語句不會執行,直到再次被啓動;
it.next(4).value; // undefined;  y = 7; 第三次調用next方法時傳入一個值,yield表達式可以接收值,也可以生成值,生成的值會被next方法返回,接受的值由next方法傳入作爲整個yield表達式的值,所以此時y = 3 + 4; 然後繼續執行到下一個yield處(var z = y + (yield) ),由於yield後沒有值,所以生成值爲undefined;
it.next(5).value; // undefined; z = 12; 第四次調用next方法傳入5,可以得到z = 7 + 5; 執行到return結束,返回對象爲{value: undefined, done: true};

每次調用生成器函數構建迭代器時,同時隱式構建了生成器實例,迭代器對應執行的是新的生成器實例,因此可以構建多個迭代器來控制對應生成器實例,互相之間並不會干擾。比如

function *bar () {
	yield 1;
	yield 2;
	return;
}
var it1 = bar();
var it2 = bar();
it1.next(); // {value: 1, done: false}
it2.next(); // {value: 1, done: false},並非{value: 2, done: false}

利用生成器實例的暫停執行機制,可以控制多個生成器函數交替執行,如果這些函數有共享的變量,則可以模仿多線程競態條件環境。
for of遍歷方法
典型的for of遍歷寫法for (let v of something),其中something是迭代器對象,或者具有[Symbol.iterator]屬性的對象,如數組,Map集合和Set集合,而v則是迭代器對象調用next方法返回對象的value屬性值;for of結構中迭代器對象自動調用next方法,直到返回對象的done屬性值爲true;
如果生成器函數內部有無限多個狀態,如

function *foo () {
	var nextVal;
	while (true) {
		if (nextVal === undefined ) {
			nextVal = 1;
		} else {
			nextVal = 2 * nextVal;
		}
		yield nextVal;
	}
}

利用for ( let v of foo())則會一直無限循環下去,那麼如何讓生成器停止呢?

給for of添加break、return語句;for of結構在遇到break、return或者有異常時,並非會掛起狀態,而是會向迭代器對象發送一個信號使其終止;break和return會觸發運行生成器內部的finally語句;

var it = foo();
for ( let v of it ) {
	console.log(v);
	if ( v > 500 ) {
		break; // 或者用return
		// it.return('done!'); 迭代器對象調用return方法來發出終止信號,並且設置返回對象爲{value: 'done', done: true};
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章