ES6的改版,主要是通过引入JAVA等静态语言的优秀思想来解决老版本的一些痼疾,如作用域,回调,继承和封装等问题。这些改革措施是非常成功的,ES6让JS真正变成了一种好用的语言。这里是关于Reflect和Proxy。

Set
之前的JS只提供了两种容器:数组和对象。es6又添加了另一种非常有用的数据结构:Set。他就是集合的意思,本身也是一种容器。
既然是容器,肯定有对应的增查改删的操作了。增查改删是容器必备的职能。那么这种新式容器,到底有什么特点呢?
拿他跟数组比较的话,Set的最大的特点就是每个值都是唯一的,不能有重复值。经常会遇到数组去重的问题吧?自从有了Set,就开始变得美好了。
1  | let container = new Set([1, 2, 2, 3, 4, 4]);//可以直接传入数组进行初始化  | 
Set的构造方法可以直接传数组进行初始化,当然也可以这样声明:let mySet = new Set();
Set跟数组极为类似,二者可以互相转换着用。有了它,就可以轻松的解决数组去重问题了。
1  | //简单去重方案  | 
这并不适用于含有重复对象的数组,因为对象是比较的是内存地址。1
2
3console.log({}=={});//false,内存地址不同
let arr = [{},{},{}];
console.log([...new Set(arr)]);//对象是无法去重的
对象数组到底如何去重呢?
一种办法是你需要递归比较,两个对象的每一个值是否相等,不等的放入一个新数组中,相等的跳过。但是这个方法很普通,可以利用Set的不重复特性,把对象先转成字符串存入Set,去掉重复值后,再转回来就好。
1  | function unique(arr){  | 
新数据结构:Map
这个是Map容器,而不是前面的map()方法,千万别弄混了(注意大小写)!Map就是键值对容器,跟Object非常类似。它有什么特别之处呢?
其实Object有个很大的问题:就是键只能用字符串,而不能使用其他数据类型。
如果让键不限于字符串,而是各种数据类型呢?比如num?
1  | <!DOCTYPE html>  | 
一般来说,对象的键应该是唯一的。Object的键因为是字符串,所以没啥问题,但Map既然放开了类型限制,这就得注意了
1  | 
  | 
因为对象比较的是内存地址,所以['a']作为新开辟的空间,无法在Map容器中找到。
再来看一下Map的增查改删,非常简单。
1  | //利用二维数组,可以构建Map  | 
获取的keys集合是MapIterator类型的,这叫遍历器。顾名思义,就是专供遍历用的一种数据结构
Reflect是面镜子
Reflect就是反射的意思,那究竟反射啥呢?
大家知道镜子可以反射吧?Reflect就是一面镜子。那是谁照镜子呢?就是Object。
也就是说,Object把自己的属于语言内部的方法(比如Object.defineProperty)照到了Reflect上。
1  | <!DOCTYPE html>  | 
Reflect一共是13个静态方法,就是13种武器哈:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
Reflect.apply(target,thisArg,args)
Reflect.construct(target,args)
Reflect.get(target,name,receiver)
Reflect.set(target,name,value,receiver)
Reflect.defineProperty(target,name,desc)
Reflect.deleteProperty(target,name)
Reflect.has(target,name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)
看下几个常用的方法。
1  | 
  | 
他与Proxy结合使用更合理。
Proxy
Proxy就是拦截器,也可以译为代理器,跟设计模式的代理模式差不多。他跟Reflect是一一对应的。
只要Proxy对象有的方法,Reflect对象上都有。当然咯,Proxy没有的,Reflect也有。
拦截器本身也是对象,他的主要作用在于拦截。看一下语法定义:var proxy = new Proxy(target, handler);
1.target就是目标对象,我们要给哪个对象加拦截?
2.handler就是处理对象,他是一系列拦截操作的集合。这些拦截操作,就是对应的Reflect具有的十三种静态方法(所谓的一一对应其实就是说的这个)。注意,只有这十三种武器,不支持其他的。
拿最简单的set方法为例:
1  | //形参说明:  | 
createValidator这个函数,返回的是Proxy拦截器对象。这个拦截器对象,对原Person类的set操作做了修改,加入了一些验证方案,其实就是起到了包装增强的作用,让Person具有了可验证字段类型的功能。
再来看下Reflect.apply的用法。这个方法的使用频率还是蛮高的
1  | //假如这个foo函数是同事张三写的  | 
结语
Proxy是用于修改语言内部行为的机制,因为Object对象内部的方法大多属于这种情况,所以handler的配置,又跟Reflect紧密联系在一起(因为Reflect是Object的镜子嘛)。
应该说,Reflect和Proxy之间的关系还是不太容易理顺的。