1.Proxy和Reflect攔截
2.Iterator遍歷器
一、Proxy和Reflect
1.概念
Proxy代理,攔截作用。
2.語法
var proxy = new Proxy(target, handler);
target是目標對象,handler是攔截不同方法的聲明。
handler事件:get、set、has、deleteProperty、ownKeys、getOwnPropertyDescriptor、defineProperty、preventExtensions、getPrototypeOf、isExtensible、setPrototypeOf、apply、construct。
具體每種事件對應什麼方法,詳見http://caibaojian.com/es6/proxy.html
3.
Proxy.revocable方法返回一個可取消的Proxy實例。
4.this指向
在 Proxy 代理的情況下,目標對象內部的this關鍵字會指向 Proxy 代理。
5.Reflect概念
修改了Object的一些方法,改爲函數調用,返回布爾值更爲合理,爲Proxy操作對象的事件提供便利。
6.Reflect方法
同Proxy的handler支持的事件一致。
二、Iterator遍歷器
1.作用
- 爲四種數據集合(Array/Object/Map/Set)提供統一的接口機制。
- 使得數據結構的成員能夠按某種次序排列。
- ES6創造了一種新的遍歷命令for…of循環,Iterator接口主要供for…of消費。
2.遍歷過程
(1)創建一個指針對象,指向當前數據結構的起始位置。也就是說,遍歷器對象本質上,就是一個指針對象。
(2)第一次調用指針對象的next方法,可以將指針指向數據結構的第一個成員。
(3)第二次調用指針對象的next方法,指針就指向數據結構的第二個成員。
(4)不斷調用指針對象的next方法,直到它指向數據結構的結束位置。
每一次調用next方法,都會返回數據結構的當前成員的信息。
3.原理
一個數據結構只要具有Symbol.iterator屬性,就可以認爲是“可遍歷的”(iterable)。
遍歷器對象的根本特徵就是具有next方法。每次調用next方法,都會返回一個代表當前成員的信息對象,具有value和done兩個屬性。
舉例:
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}
};
4.調用Iterator接口的場合
1)解構賦值
對數組和Set結構進行解構賦值時,會默認調用Symbol.iterator方法。
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];
2)擴展運算符
3)yield*
4)其他場合
由於數組的遍歷會調用遍歷器接口,所以任何接受數組作爲參數的場合,其實都調用了遍歷器接口。
- for…of
- Array.from()
- Map(), Set(), WeakMap(), WeakSet()
- Promise.all()
- Promise.race()
三、generator函數
是ES6提供的一種異步編程解決方案,語法行爲與傳統函數完全不同。
1.理解
- 語法上,首先可以把它理解成,Generator函數是一個狀態機,封裝了多個內部狀態。
- 形式上,Generator函數是一個普通函數,但是有兩個特徵。一是,function關鍵字與函數名之間有一個星號;二是,函數體內部使用yield語句,定義不同的內部狀態
2.返回
返回一個狀態對象{value:'1',done:'false'}
只能通過調用next方法進入下一個狀態。
舉例:
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next();// { value: 'hello', done: false }
3.yield語句
運行邏輯:
(1)遇到yield語句,就暫停執行後面的操作,並將緊跟在yield後面的那個表達式的值,作爲返回的對象的value屬性值。
(2)下一次調用next方法時,再繼續往下執行,直到遇到下一個yield語句。
(3)如果沒有再遇到新的yield語句,就一直運行到函數結束,直到return語句爲止,並將return語句後面的表達式的值,作爲返回的對象的value屬性值。
(4)如果該函數沒有return語句,則返回的對象的value屬性值爲undefined。
注意:
- 只能出現在generator函數中,函數作爲參數的情況中也不能使用。
- 如果用在一個表達式之中,必須放在圓括號裏面。
console.log('Hello' + (yield 123)); // OK
- 用作函數參數或賦值表達式的右邊,可以不加括號。
foo(yield 'a', yield 'b'); // OK
let input = yield; // OK
4.yield*
如果在Generater函數內部,調用另一個Generator函數,默認情況下是沒有效果的。
這個就需要用到yield*語句,用來在一個Generator函數裏面執行另一個Generator函數。
function* foo() {
yield 'a';
yield 'b';
}
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
// 等同於
function* bar() {
yield 'x';
yield 'a';
yield 'b';
yield 'y';
}
function* gen(){
yield* ["a", "b", "c"];
}
gen().next() // { value:"a", done:false }
yield命令後面如果不加星號,返回的是整個數組,加了星號就表示返回的是數組的遍歷器對象。
5.與Iterator接口的關係
iterator對象最重要的Symbol.iterator屬性,就是調用next()方法遍歷數組中下一個對象,並返回{value:’’,done:false}遍歷器對象。這可以通過generator函數實現。
可以把Generator賦值給對象的Symbol.iterator屬性,從而使得該對象具有Iterator接口。
6.next
yield句本身沒有返回值,或者說總是返回undefined。next方法可以帶一個參數,該參數就會被當作上一個yield語句的返回值。
7.函數
throw
在函數體外拋出錯誤,然後在Generator函數體內捕獲。
return
可以返回給定的值,並且終結遍歷Generator函數。
8.其他
返回的總是遍歷器對象,而不是this對象。
Generator函數也不能跟new命令一起用,會報錯。
Generator是實現狀態機的最佳結構。
9.協程
可以理解成“協作的線程”或“協作的函數”。協程既可以用單線程實現,也可以用多線程實現。
從實現上看,在內存中,子例程只使用一個棧(stack),而協程是同時存在多個棧,但只有一個棧是在運行狀態,也就是說,協程是以多佔用內存爲代價,實現多任務的並行。