Proxy 用于修改某些操做的默认行为;能够理解成,在目标对象以前架设一层"拦截",外界对对象的访问,都必须先经过这层拦截,所以提供了一层机制,能够对外界的访问进行过滤和改写。javascript
const proxy = new Proxy(target,handler); target表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。 const obj = new Proxy({}, { get: function(target, key, receiver) { console.log(`getting ${key}`); return Reflect.get(target, key, receiver); }, set: function(target, key, value,receiver) { console.log(`setting ${key}`) return Reflect.set(target, key, value, receiver) } }) obj.count = 1 console.log(++obj.count)//2
get(target,prop,receiver ):拦截某个属性的读取,三个参数依次为目标对象、属性名和 proxy 实例自己 receiver, 其中 receiver 为可选;java
function createArray(...elements) { let handler = { get(target, propKey, receiver) { console.log(propKey) let index = Number(propKey); if(index < 0) { propKey = String(target.length + index); } return Reflect.get(target, propKey, receiver) } }; let target = []; target.push(...elements); return new Proxy(target, handler); } let arr = createArray('a','b','c'); console.log(arr[-1]);// c console.log(arr[0]);// b console.log(arr[1])// a
这个例子用 get 拦截,实现根据数组索引读取数组;当索引为负时,表示数组遍历为从后到前;因此,当数组的位置是 -1 的时候,就会输出数组的倒数第一个成员 c数组
set(target,prop, value, receiver):用来拦截某个属性的赋值操做; prop 为属性名,value 为属性值,receiver 依旧可选;app
用set()做为数据验证:函数
let validator= { set: function(obj,prop,value) { if(prop ==='age') { if(!Number.isInteger(value)) { throw new TypeError('The age is not an integer') } if(value > 200) { throw new RangeError('The age seems invalid') } } // 对于age之外的属性,直接保存 obj[prop] = value; } } let person = new Proxy({}, validator) person.age = 100; console.log(person.age)// 100 person.age = 300; console.log(person.age);// 报错
任何不符合要求的age属性赋值,都会报错。this
apply(target,ctx, args):拦截函数的调用,call 和 apply 操做;参数 ctx 指的是目标对象的上下文对象 (this) 和目标对象的参数数组。代理
const twice = { apply(target, ctx, args) { console.log(args);// 1,2 return Reflect.apply(...arguments)*2; } }; function sum(left, right) { return left + right; }; const proxy = new Proxy(sum,twice); console.log(proxy(1,2));//6
当执行proxy()时,会被apply()拦截;code
has(target,key):用来拦截 hasProperty 操做,即判断对象是否具备某个属性;典型的操做就是 in 运算符。对象
const handler = { has(target,key) { if(key[0] === '_') { return false; } return key in target; } }; const target = {_prop: 'foo', prop: 'foo'}; const proxy = new Proxy(target,handler); console.log('_prop' in proxy);// false;
这里的代码中,若是原对象的属性名的第一个字符时下划线,proxy.has() 就会返回 false,从而不被 in 运算符发现。注意:has() 拦截的是hasProperty 操做,而不是 hasOwnProperty 操做,即它不判断属性来源。索引
虽然 proxy 能够代理针对目标对象的访问,但它不是目标对象的透明代理。不作任何拦截的状况下,也没法保证与目标对象的行为一致。主要缘由就是在Proxy 代理的状况下,目标对象内部的 this 会指向 Proxy 代理。
const target = { m: function () { console.log(this === proxy) } } const handler = {}; const proxy = new Proxy(target,handler); target.m()// false proxy.m()// true
上面代码中,一旦 proxy 代理 target.m,后者内部的 this 就指向了 proxy 而不是 target 了。