JavaScript之生成器_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
generator(生成器)是ES6標(biāo)準(zhǔn)引入的新的數(shù)據(jù)類型。一個(gè)generator看上去像一個(gè)函數(shù),但可以返回多次。
我們先復(fù)習(xí)函數(shù)的概念。一個(gè)函數(shù)是一段完整的代碼,調(diào)用一個(gè)函數(shù)就是傳入?yún)?shù),然后返回結(jié)果:
function foo(x) {
return x + x;
}
var r = foo(1); // 調(diào)用foo函數(shù)
函數(shù)在執(zhí)行過程中,如果沒有遇到return語(yǔ)句(函數(shù)末尾如果沒有return,就是隱含的return undefined;),控制權(quán)無(wú)法交回被調(diào)用的代碼。
generator跟函數(shù)很像,定義如下:
function* foo(x) {
yield x + 1;
yield x + 2;
return x + 3;
}
generator和函數(shù)不同的是,generator由function*定義(注意多出的*號(hào)),并且,除了return語(yǔ)句,還可以用yield返回多次。
大多數(shù)同學(xué)立刻就暈了,generator就是能夠返回多次的“函數(shù)”?返回多次有啥用?
還是舉個(gè)栗子吧。
我們以一個(gè)著名的斐波那契數(shù)列為例,它由0,1開頭:
0 1 1 2 3 5 8 13 21 34 ...
要編寫一個(gè)產(chǎn)生斐波那契數(shù)列的函數(shù),可以這么寫:
function fib(max) {
var
t,
a = 0,
b = 1,
arr = [0, 1];
while (arr.length < max) {
t = a + b;
a = b;
b = t;
arr.push(t);
}
return arr;
}
// 測(cè)試:
fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
函數(shù)只能返回一次,所以必須返回一個(gè)Array。但是,如果換成generator,就可以一次返回一個(gè)數(shù),不斷返回多次。用generator改寫如下:
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 1;
while (n < max) {
yield a;
t = a + b;
a = b;
b = t;
n ++;
}
return a;
}
直接調(diào)用試試:
fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}
直接調(diào)用一個(gè)generator和調(diào)用函數(shù)不一樣,fib(5)僅僅是創(chuàng)建了一個(gè)generator對(duì)象,還沒有去執(zhí)行它。
調(diào)用generator對(duì)象有兩個(gè)方法,一是不斷地調(diào)用generator對(duì)象的next()方法:
var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: true}
next()方法會(huì)執(zhí)行g(shù)enerator的代碼,然后,每次遇到yield x;就返回一個(gè)對(duì)象{value: x, done: true/false},然后“暫?!薄7祷氐?code>value就是yield的返回值,done表示這個(gè)generator是否已經(jīng)執(zhí)行結(jié)束了。如果done為true,則value就是return的返回值。
當(dāng)執(zhí)行到done為true時(shí),這個(gè)generator對(duì)象就已經(jīng)全部執(zhí)行完畢,不要再繼續(xù)調(diào)用next()了。
第二個(gè)方法是直接用for ... of循環(huán)迭代generator對(duì)象,這種方式不需要我們自己判斷done:
for (var x of fib(5)) {
console.log(x); // 依次輸出0, 1, 1, 2, 3
}
generator和普通函數(shù)相比,有什么用?
因?yàn)間enerator可以在執(zhí)行過程中多次返回,所以它看上去就像一個(gè)可以記住執(zhí)行狀態(tài)的函數(shù),利用這一點(diǎn),寫一個(gè)generator就可以實(shí)現(xiàn)需要用面向?qū)ο蟛拍軐?shí)現(xiàn)的功能。例如,用一個(gè)對(duì)象來(lái)保存狀態(tài),得這么寫:
var fib = {
a: 0,
b: 1,
n: 0,
max: 5,
next: function () {
var
r = this.a,
t = this.a + this.b;
this.a = this.b;
this.b = t;
if (this.n < this.max) {
this.n ++;
return r;
} else {
return undefined;
}
}
};
用對(duì)象的屬性來(lái)保存狀態(tài),相當(dāng)繁瑣。
generator還有另一個(gè)巨大的好處,就是把異步回調(diào)代碼變成“同步”代碼。這個(gè)好處要等到后面學(xué)了AJAX以后才能體會(huì)到。
沒有g(shù)enerator之前的黑暗時(shí)代,用AJAX時(shí)需要這么寫代碼:
ajax('http://url-1', data1, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-2', data2, function (err, result) {
if (err) {
return handle(err);
}
ajax('http://url-3', data3, function (err, result) {
if (err) {
return handle(err);
}
return success(result);
});
});
});
回調(diào)越多,代碼越難看。
有了generator的美好時(shí)代,用AJAX時(shí)可以這么寫:
try {
r1 = yield ajax('http://url-1', data1);
r2 = yield ajax('http://url-2', data2);
r3 = yield ajax('http://url-3', data3);
success(r3);
}
catch (err) {
handle(err);
}
看上去是同步的代碼,實(shí)際執(zhí)行是異步的。
練習(xí)
要生成一個(gè)自增的ID,可以編寫一個(gè)next_id()函數(shù)
相關(guān)文章
JavaScript合并兩個(gè)數(shù)組并去除重復(fù)項(xiàng)的方法
這篇文章主要介紹了JavaScript合并兩個(gè)數(shù)組并去除重復(fù)項(xiàng)的方法,涉及javascript操作數(shù)組的合并與去重的相關(guān)技巧,需要的朋友可以參考下2015-06-06
js如何判斷對(duì)象數(shù)組中是否存在某個(gè)對(duì)象
這篇文章主要介紹了js如何判斷對(duì)象數(shù)組中是否存在某個(gè)對(duì)象問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
javascript實(shí)現(xiàn)阻止iOS APP中的鏈接打開Safari瀏覽器
這篇文章主要介紹了javascript實(shí)現(xiàn)阻止iOS APP中的鏈接打開Safari瀏覽器,這個(gè)IOS APP一般是Web APP,否則沒法使用本文的代碼,需要的朋友可以參考下2014-06-06
js 判斷當(dāng)前時(shí)間是否處于某個(gè)一個(gè)時(shí)間段內(nèi)
這篇文章主要介紹了js 判斷當(dāng)前時(shí)間是否處于某個(gè)一個(gè)時(shí)間段內(nèi),使用 jutils - JavaScript常用函數(shù)庫(kù)的 isDuringDate 函數(shù)來(lái)實(shí)現(xiàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
JavaScript中的方法調(diào)用詳細(xì)介紹
這篇文章主要介紹了JavaScript中的方法調(diào)用詳細(xì)介紹,JavaScript中,如果function屬于一個(gè)對(duì)象,那么通過對(duì)象來(lái)訪問該function的行為稱之為“方法調(diào)用”,需要的朋友可以參考下2014-12-12
JS,Jquery獲取select,dropdownlist,checkbox下拉列表框的值(示例代碼)
本篇文章主要是對(duì)JS,Jquery獲取select,dropdownlist,checkbox下拉列表框的值(示例代碼)進(jìn)行了介紹,需要的朋友可以過來(lái)參考下,希望對(duì)大家有所幫助2014-01-01

