javascript學習筆記(14)--generator

什麼是generator

generator(生成器)是ES6標準引入的新的數據類型。一個generator看上去像一個函數,但可以返回多次

generator定義

先複習函數的概念,一個函數是一段完整的代碼,調用一個函數就是傳入參數,然後返回結果

 function foo(x) { return x + x; }
 var r = foo(1); 

函數在執行過程中,如果沒有遇到return語句(函數末尾如果沒有return,就是隱含的return undefined;)控制權則無法交回被調用的代碼
generator跟函數很像,定義如下

 function* foo(x) { yield x + 1; yield x + 2; return x + 3; }

generator由function*定義(注意多出的*號),並且除了return語句,還可以用yield返回多次

以著名的斐波那契數列爲例,要編寫一個產生斐波那契數列的函數,可以這麼寫

 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; }
  fib(5); // [0, 1, 1, 2, 3] 
  fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 

函數只能返回一次,所以必須返回一個Array

但是,如果換成generator,就可以一次返回一個數,不斷返回多次
用 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; }
  fib(5); // Generator {  }

調用一個generator和調用函數不一樣,fib(5)僅僅是創建了一個generator對象,還沒有去執行它

genertor使用方法

調用generator對象有兩個方法
一是不斷地調用generator對象的next()方法

var f = fib(5); 
f.next(); //Object { value: 0, done: false }
f.next(); // Object { value: 1, done: false }
f.next(); //Object { value: 1, done: false }
 f.next(); // Object { value: 2, done: false }
  f.next(); //Object { value: 3, done: true }
  
  f.next();//Object { value: undefined, done: true }

next()方法會執行generator的代碼,然後,每次遇到yield x;就返回一個對象{value: x, done: false},然後“暫停”,返回的value就是yield的返回值,done表示這個generator是否已經執行結束了
如果有return的話,會在返回最後一個結果的時候done變成true,如果全部用的是yield的話,就會再返回完所有的結果之後,返回 { value: undefined, done: true }
當執行到done爲true時,這個generator對象就已經全部執行完畢,如果再調用就會返回undefined

 f.next();//Object { value: undefined, done: true }

簡單的看一下有沒有return的區別
有return

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; };
var f=fib(2);
f.next();
Object { value: 0, done: false }
f.next();
Object { value: 1, done: true }
f.next();
Object { value: undefined, done: true }

沒有return

function* fib(max) {
 var t,a = 0,b = 1, n = 1; 
 while (n < max) {
  yield a; t = a + b; a = b; b = t; n ++; }
 yield a; };
var f=fib(2);
f.next();
Object { value: 0, done: false }
f.next()
Object { value: 1, done: false }
f.next()
Object { value: undefined, done: true }

區別就在最後一個結果上,看看就明白了

第二個方法是直接用for … of循環迭代generator對象,這種方式不需要我們自己判斷done
emm我也突然發現,有沒有return在這裏也有區別
有return

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; };
for (var x of fib(5)) { console.log(x); }
0 
1
1 
2

沒有return

 function* fib(max) {
 var t,a = 0,b = 1, n = 1; 
 while (n < max) {
  yield a; t = a + b; a = b; b = t; n ++; }
 yield a; };
for (var x of fib(5)) { console.log(x); }
0
1
1
2
3

盲猜這個的原理還是根據done是否爲false,由於第一個有return的最後一個結果done是true,所以只返回了4個,第二個5個結果都是false,就返回了5個

有什麼用

因爲generator可以在執行過程中多次返回,所以它看上去就像一個可以記住執行狀態的函數
而如果我們不用generator來保存狀態,一個可行的方法就是用對象保存
用對象來保存狀態,得這麼寫

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; } } };

用對象的屬性來保存狀態,相當繁瑣

generator還有另一個巨大的好處,就是把異步回調代碼變成“同步”代碼,這一點會在後面的AJAX體現,現在我們的功力還不夠,還需要修煉修煉

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章