從零開始學 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
表示式(hello
和world
),即該函式有三個狀態: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
方法,就會返回一個有著value
和done
兩個屬性的物件。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
表示式本身沒有返回值,或者說總是返回undefined
。next
方法可以帶一個引數,該引數就會被當作上一個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
屬性為true
,for...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 之 Ajax(二)PHP基礎語法
一、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 之 CSS3(五)transform
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 之 DOM(一)DOM的概念,對標簽操作
關註 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 之 Ajax(六)jQuery中的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 之 CSS3(一)CSS3概述,選擇器
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前端之
從零開始學Web之HTML(二)標籤、超連結、特殊符號、列表、音樂、滾動、head等
大家好,這裡是 Daotin 從零開始學 Web 系列教程。此文首發於「 Daotin的夢囈 」,歡迎大家訂閱關注。在這裡我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的專案。現在就讓我們一起進入 Web 前端學習的冒險之旅吧! 一、標籤 1、單標籤 註釋標籤