1. 程式人生 > >從零開始學 Web 之 ES6(五)ES6基礎語法三

從零開始學 Web 之 ES6(五)ES6基礎語法三

一、Generator

Generator 函式是 ES6 提供的一種非同步程式設計解決方案。

Generator 函式有多種理解角度。語法上,首先可以把它理解成,Generator 函式是一個狀態機,封裝了多個內部狀態。

執行 Generator 函式會返回一個遍歷器物件,也就是說,Generator 函式除了狀態機,還是一個遍歷器物件生成函式。返回的遍歷器物件,可以依次遍歷 Generator 函式內部的每一個狀態。

形式上,Generator 函式是一個普通函式,但是有兩個特徵。

一是,function關鍵字與函式名之間有一個星號;

二是,函式體內部使用yield表示式,定義不同的內部狀態(yield

在英語裡的意思就是“產出”)。

function* myGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
// 返回值是一個遍歷器物件
var hw = myGenerator();

上面程式碼定義了一個 Generator 函式helloWorldGenerator,它內部有兩個yield表示式(helloworld),即該函式有三個狀態:hello,world 和 return 語句(結束執行)。

然後,Generator 函式的呼叫方法與普通函式一樣,也是在函式名後面加上一對圓括號。不同的是,呼叫 Generator 函式後,該函式並不執行,返回的也不是函式執行結果,而是一個指向內部狀態的指標物件,也就是上一章介紹的遍歷器物件(Iterator Object)。

下一步,必須呼叫遍歷器物件的next方法,使得指標移向下一個狀態。也就是說,每次呼叫next方法,內部指標就從函式頭部或上一次停下來的地方開始執行,直到遇到下一個yield表示式(或return語句)為止。換言之,Generator 函式是分段執行的,yield表示式是暫停執行的標記,而next方法可以恢復執行。

hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

總結一下,呼叫 Generator 函式,返回一個遍歷器物件,代表 Generator 函式的內部指標。以後,每次呼叫遍歷器物件的next方法,就會返回一個有著valuedone兩個屬性的物件。value屬性表示當前的內部狀態的值,是yield表示式後面那個表示式的值;done屬性是一個布林值,表示是否遍歷結束。

1、yield 表示式

由於 Generator 函式返回的遍歷器物件,只有呼叫next方法才會遍歷下一個內部狀態,所以其實提供了一種可以暫停執行的函式。yield表示式就是暫停標誌。

遍歷器物件的next方法的執行邏輯如下:

(1)遇到yield表示式,就暫停執行後面的操作,並將緊跟在yield後面的那個表示式的值,作為返回的物件的value屬性值。

(2)下一次呼叫next方法時,再繼續往下執行,直到遇到下一個yield表示式。

(3)如果沒有再遇到新的yield表示式,就一直執行到函式結束,直到return語句為止,並將return語句後面的表示式的值,作為返回的物件的value屬性值。

(4)如果該函式沒有return語句,則返回的物件的value屬性值為undefined

需要注意的是,yield表示式後面的表示式,只有當呼叫next方法、內部指標指向該語句時才會執行,因此等於為 JavaScript 提供了手動的“惰性求值”(Lazy Evaluation)的語法功能。

yield表示式與return語句區別:

相似之處在於,都能返回緊跟在語句後面的那個表示式的值。區別在於每次遇到yield,函式暫停執行,下一次再從該位置繼續向後執行,而return語句不具備位置記憶的功能。

一個函式裡面,只能執行一次(或者說一個)return語句,但是可以執行多次(或者說多個)yield表示式。

正常函式只能返回一個值,因為只能執行一次return;Generator 函式可以返回一系列的值,因為可以有任意多個yield

2、與 Iterator 介面的關係

任意一個物件的Symbol.iterator方法,等於該物件的遍歷器生成函式,呼叫該函式會返回該物件的一個遍歷器物件。

由於 Generator 函式就是遍歷器生成函式,因此可以把 Generator 賦值給物件的Symbol.iterator屬性,從而使得該物件具有 Iterator 介面。

var myIterable = {};
myIterable[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};

[...myIterable] // [1, 2, 3]

上面程式碼中,Generator 函式賦值給Symbol.iterator屬性,從而使得myIterable物件具有了 Iterator 介面,可以被...運算子遍歷了。

3、next 方法的引數

yield表示式本身沒有返回值,或者說總是返回undefinednext方法可以帶一個引數,該引數就會被當作上一個yield表示式的返回值。

function* f() {
  for(var i = 0; true; i++) {
    var reset = yield i;
    if(reset) { i = -1; }
  }
}

var g = f();

g.next() // { value: 0, done: false }
g.next() // { value: 1, done: false }
g.next(true) // { value: 0, done: false }

上面程式碼先定義了一個可以無限執行的 Generator 函式f,如果next方法沒有引數,每次執行到yield表示式,變數reset的值總是undefined。當next方法帶一個引數true時,變數reset就被重置為這個引數(即true),因此i會等於-1,下一輪迴圈就會從-1開始遞增。

4、for...of 迴圈

for...of迴圈可以自動遍歷 Generator 函式時生成的Iterator物件,且此時不再需要呼叫next方法。

function* foo() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
  return 6;
}

for (let v of foo()) {
  console.log(v);
}
// 1 2 3 4 5

上面程式碼使用for...of迴圈,依次顯示 5 個yield表示式的值。這裡需要注意,一旦next方法的返回物件的done屬性為truefor...of迴圈就會中止,且不包含該返回物件,所以上面程式碼的return語句返回的6,不包括在for...of迴圈之中。

下面是一個利用 Generator 函式和for...of迴圈,實現斐波那契數列的例子。

function* foo() {
      let [prev, current] = [0, 1];
      for (;;) {
        yield current;
        [prev, current] = [current, prev + current];
      }
    }

    for (let n of foo()) {
      if (n > 1000) break;
      console.log(n);
    }

Generator小案例

需求:

1、傳送Ajax請求獲取新聞內容

2、新聞內容獲取成功再次傳送請求獲取對應的新聞評論內容

3、新聞內容獲取失敗則不需要再次傳送請求。

    function getNews(url) {
      $.get(url, function (data) {
        console.log(data);
        let urls = "http://localhost:3000" + data.commentUrl;
        // urls可以作為第一個yield的返回值
        // 執行第二條yeild語句,傳送請求新聞評論
        // 獲取的評論地址如何傳入到 yield getNews(urls);靠的是第二次
        // 傳送next時傳入的引數,就是評論地址
        sx.next(urls);
      });
    }

    function* sendXml() {
      // 傳送請求新聞內容
      let urls = yield getNews("http://localhost:3000/news?id=2");
      // 請求新聞評論內容
      yield getNews(urls);
    }

    let sx = sendXml();
    // 執行第一條yeild語句,傳送請求新聞
    sx.next();

二、async

ES2017 標準引入了 async 函式,使得非同步操作變得更加方便。

async 函式是什麼?一句話,它就是 Generator 函式的語法糖。

語法:

async function foo(){
  await 非同步操作;
  await 非同步操作;
}

特點:

1、不需要像Generator去呼叫next方法,遇到await等待,當前的非同步操作完成就往下執行

2、返回的總是Promise物件,可以用then方法進行下一步操作

3、async取代Generator函式的星號*,await取代Generator的yield

4、語意上更為明確,使用簡單,經臨床驗證,暫時沒有任何副作用

舉個栗子:

    async function timeout(ms) {
      return new Promise(resolve => {
        setTimeout(resolve, ms);
      })
    }
    
    async function asyncPrint(value, ms) {
      console.log('函式執行', new Date().toTimeString());
      await timeout(ms);
      console.log('延時時間', new Date().toTimeString());
      console.log(value);
    }

    console.log(asyncPrint('hello async', 2000));

asyncPrint 執行的時候,先列印的是“函式執行”,之後進入到 timeout 函式,由於是非同步執行,但是timeout未執行完成,所以 await 在等待,相當於掛起。而這一邊 asyncPrint會立即返回一個 Promise物件。之後另一邊timeout、執行完成,打印出“延時時間”,之後列印“hello async”。

async函式內部return語句返回的值,會成為then方法回撥函式的引數。下面程式碼中,函式f內部return命令返回的值,會被then方法回撥函式接收到。

async function f() {
  return 'hello world';
}

f().then(v => console.log(v))
// "hello world"

1、await 命令

正常情況下,await命令後面是一個 Promise 物件。如果不是,會被轉成一個立即resolve的 Promise 物件。

resolve引數就是await的返回值。

async function f() {
  return await 123;
}

f().then(v => console.log(v))
// 123

await命令後面的 Promise 物件如果變為reject狀態,則reject的引數會被catch方法的回撥函式接收到。

async function f() {
  await Promise.reject('出錯了');
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出錯了

2、案例:獲取新聞和評論內容

async function sendXml(url) {
      return new Promise((resolve, reject) => {
        $.ajax({
          url,
          type: 'GET',
          success: data => resolve(data),
          error: error => reject(error)
        })
      })
    }

    async function getNews(url) {
      let result = await sendXml(url);
      let result2 = await sendXml(url);
      console.log(result, result2);
    }
    getNews('http://localhost:3000/news?id=2')

三、Class

JavaScript 語言中,生成例項物件的傳統方法是通過建構函式。下面是一個例子。

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

上面這種寫法跟傳統的面嚮物件語言(比如 C++ 和 Java)差異很大,ES6 提供了更接近傳統語言的寫法,引入了 Class(類)這個概念,作為物件的模板。通過class關鍵字,可以定義類。

//定義類
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

1、constructor 方法

constructor方法是類的預設方法,通過new命令生成物件例項時,自動呼叫該方法。一個類必須有constructor方法,如果沒有顯式定義,一個空的constructor方法會被預設新增。

Class 的繼承

Class 可以通過extends關鍵字實現繼承,這比 ES5 的通過修改原型鏈實現繼承,要清晰和方便很多。

class Point {
}
// ColorPoint 繼承 Point
class ColorPoint extends Point {
}

上面程式碼定義了一個ColorPoint類,該類通過extends關鍵字,繼承了Point類的所有屬性和方法。

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 呼叫父類的constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); // 呼叫父類的toString()
  }
}

上面程式碼中,constructor方法和toString方法之中,都出現了super關鍵字,它在這裡表示父類的建構函式,用來新建父類的this物件。

子類必須在constructor方法中呼叫super方法,否則新建例項時會報錯。這是因為子類自己的this物件,必須先通過父類的建構函式完成塑造,得到與父類同樣的例項屬性和方法,然後再對其進行加工,加上子類自己的例項屬性和方法。如果不呼叫super方法,子類就得不到this物件。

相關推薦

開始 Web AjaxPHP基礎語法

一、PHP 基礎語法 1、基本結構 所有PHP程式碼都要寫到 <?php ... ?> 裡面。 PHP檔案可以和 HTML 檔案結合進行使用。 PHP檔案的預設副檔名是 ".php"。 PHP程式碼必須在伺服器上執行。 2、列印語句 echo: 的作用在頁面中輸入字串(只能列印字串,數字等

開始 Web Ajax同步異步請求,數據格式

遊記 document 空閑 name center 20px 實現 resp 也會 大家好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公眾號:Web前端之

開始 Web CSS3transform

transform transform 字面上就是變形,改變的意思。在CSS3中transform主要包括以下幾種:移動 translate,縮放scale,旋轉rotate,翻轉skew,改變旋轉軸心等。 1、元素的移動:translate 作用:使用transform實現元素的移動 語法: /*使用t

開始 Web Ajax同步非同步請求,資料格式

一、同步請求與非同步請求 同步請求:在使用者進行請求傳送之後,瀏覽器會一直等待伺服器的資料返回,如果網路延遲比較高,瀏覽器就一直卡在當前介面,直到伺服器返回資料才可進行其他操作。 非同步請求:在使用者進行請求傳送之後,瀏覽器可以自由操作頁面中其他的元素,當伺服器放回資料的時候,才觸發相應事件,對返回的資料

開始 Web CSS可見性、內容移除、精靈圖、屬性選擇器、滑動門

大家好,這裡是「 Daotin的夢囈 」從零開始學 Web 系列教程。此文首發於「 Daotin的夢囈 」公眾號,歡迎大家訂閱關注。在這裡我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的專案。現在就讓我們一起進入 Web 前端學習的冒險之旅吧! 一、CSS可見性

開始 Web DOM元素的建立

大家好,這裡是「 從零開始學 Web 系列教程 」,並在下列地址同步更新...... +------------------------------------------------------------ github:https://github.com/Daotin/Web 微信公眾號:Web前端之

開始 Web jQuery操作元素其他屬性,為元素繫結事件

一、操作元素的寬和高 1、方法一 元素.css("width"); 元素.css("height"); 最後得到的是字串型別的,比如 200px。 如果我們在設定為原來寬高2倍的時候,就要先把獲取的寬高轉換成數字型別,再乘以2,這樣操作比較麻煩,有沒有簡單的方法呢? 2、方法二 元素.width(屬性

開始 Web JavaScript面向物件

大家好,這裡是「 Daotin的夢囈 」從零開始學 Web 系列教程。此文首發於「 Daotin的夢囈 」公眾號,歡迎大家訂閱關注。在這裡我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的專案。現在就讓我們一起進入 Web 前端學習的冒險之旅吧! 一、面向物件 1、

開始 Web DOMDOM的概念,對標簽操作

關註 1.5 pan 什麽 tin p標簽 nod text == 大家好,這裏是「 Daotin的夢囈 」從零開始學 Web 系列教程。此文首發於「 Daotin的夢囈 」公眾號,歡迎大家訂閱關註。在這裏我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,

開始 Web DOM節點

def clas scrip while p標簽 設置 ner 操作 text 大家好,這裏是「 Daotin的夢囈 」從零開始學 Web 系列教程。此文首發於「 Daotin的夢囈 」公眾號,歡迎大家訂閱關註。在這裏我會從 Web 前端零基礎開始,一步步學習 Web 相

開始 Web jQuery獲取和操作元素的屬性

eight images idt 隱藏 lis 屬性 ner master lin 大家好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公眾號:Web前端之巔

開始 Web jQuery為元素綁定多個相同事件,解綁事件

png 好用 添加 方式 執行 存在 區別 也會 地址 大家好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公眾號:Web前端之巔 博客園:http://ww

開始 Web jQuery事件冒泡,事件參數對象,鏈式編程原理

eval uri turn 定位 return 也會 否則 ont sele 大家好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公眾號:Web前端之巔 博客

開始 Web AjaxjQuery中的Ajax

var 技術分享 else parse cnblogs 我會 clas alt jquer 大家好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公眾號:Web

開始 Web HTML5表單,多媒體新增內容,新增獲取操作元素,自定義屬性

器) user 對比 style 按鈕 ont mp3 url -- 大家好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公眾號:Web前端之巔 博客園:ht

開始 Web CSS3CSS3概述,選擇器

https 兼容問題 3.1 線性 web前端 不同 錨點 splay lock 大家好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公眾號:Web前端之巔

開始 Web CSS選擇器

大家好,這裡是「 Daotin的夢囈 」從零開始學 Web 系列教程。此文首發於「 Daotin的夢囈 」公眾號,歡迎大家訂閱關注。在這裡我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的專案。現在就讓我們一起進入 W

開始 Web CSS3顏色模式,文字陰影,盒模型,邊框圓角,邊框陰影

一、顏色模式 顏色模式有兩種: RGBA rgba(0,0,0,0.5); //黑色,透明度0.5 HSLA(顏色(0~360),飽和度(0%~100%),明度(0%~100%),透明度(0~1)) 紅橙黃綠青藍紫紅:顏色從 0~360 順序,各佔30度。比如紅色為0,黃色為120,綠色為240。

開始 Web DOM為元素繫結與解綁事件

大家好,這裡是「 從零開始學 Web 系列教程 」,並在下列地址同步更新...... +------------------------------------------------------------ github:https://github.com/Daotin/Web 微信公眾號:Web前端之

開始WebHTML標籤、超連結、特殊符號、列表、音樂、滾動、head等

大家好,這裡是 Daotin 從零開始學 Web 系列教程。此文首發於「 Daotin的夢囈 」,歡迎大家訂閱關注。在這裡我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的專案。現在就讓我們一起進入 Web 前端學習的冒險之旅吧! 一、標籤 1、單標籤 註釋標籤