Proxy
Proxy可以理解成,在目标对象之前架一层‘拦截’,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由它来‘代理’某些操作,可以译为“代理器”
var proxy = new Proxy(target,handler);
Proxy对象的所有用法,都是上面这种形式,不同的只是handler参数的写法,其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为
-
举一个拦截器读取属性行为的🌰
var proxy = new Proxy({}, { //get方法的两个参数:目标对象、索要访问的属性 //可以看到,拦截函数总是返回100,所以任何属性都得到35 get: function(target, property) { return 100; } }) console.log(proxy.name); // 100 console.log(proxy.time); // 100 console.log(proxy.age); // 100
注意:要使得Proxy起作用,必须针对Proxy实例进行操作,而不是针对目标对象进行操作
如果handler没有设置任何拦截,那就等同于直接通向原对象
一个技巧是将Proxy对象,设置到object.proxy属性,从而可以在object对象上调用
var object = { proxy: new Proxy(target, handler) }
-
Proxy实例也可以作为其他对象的原型对象
var proxy = new Proxy({}, { get: function(target, property) { return 100; } }) let obj = Object.create(proxy); console.log(obj.title);//100
上面代码中,proxy对象是obj对象的原型,obj对象本身并没有time属性,所以根据原型链,会在proxy对象上读取该属性,导致被拦截
同一个拦截器,可以设置多个拦截操作,如果对于可以设置,但是没有设置拦截的操作,则直接落在目标对象上,按照原先的方法产生结果
Proxy支持的拦截操作一共是13中:
- get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy['foo']。
- set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
- has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
- deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
- ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
- getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
- defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
- preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
- getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
- isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
- setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
- apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
- construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。
Reflect
Reflect对象与Proxy对象一样,也是ES6为了操作对象而提供的新的API。Reflect对象的设计目的有这样几个。
-
将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新的方法将部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法
-
修改某些Object方法的返回解构,让其变得更合理,比如Object.defineProperty(obj,name,desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj,name,desc)则会返回false
//老写法 try { Object.defineProperty(target, property, attributes) //success } catch (e) { //failure } //新写法 if(Reflect.defineProperty(target, property, attributes)){ //success }else{ //failure }
-
让Object操作都变成函数行为,某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj,name)和Reflect.deleteProperty(obj,name)让他们变成了函数行为
//老写法 'name' in obj //新写法 Reflect.has(obj,'name')
-
Reflect对象的方法与Proxy对象的方法一一对应。只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法,这就让Proxy对象可以方便的调用对应的Reflect方法,完成默认行为,作为修改行为的基础,也就是说,不管Proxy怎么修改默认行为,总可以在Reflect上获取默认行为
Proxy(target, { //Proxy方法拦截target对象的属性赋值行为。 //它采用Reflect.set方法将值赋值给对象的属性,确保完成原有的行为,然后再部署额外的功能。 set: function(target, name, value, receiver) { var success = Reflect.set(target,name, value, receiver); if (success) { console.log('property ' + name + ' on ' + target + ' set to ' + value); } return success; } });
有了Reflect对象之后,很多操作会更易读
// 老写法
Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1
// 新写法
Reflect.apply(Math.floor, undefined, [1.75]) // 1
Reflect对象一共有13个静态方法,大部分与Object对象的同名做法的作用相同,而且它与Proxy对象的方法,一一对应
- 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)
网友评论