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),而协程是同时存在多个栈,但只有一个栈是在运行状态,也就是说,协程是以多占用内存为代价,实现多任务的并行。