Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。 语法:
const p = new Proxy(target, handler)target:要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。 handler:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
实例
var obj = { name: 'xxx' } var p_obj = new Proxy(obj,{ }); console.log(p_obj.name); // xxx var obj = { name: 'xxx' } var p_obj = new Proxy(obj,{ get(target,key){ console.log('获取了getter属性'); // 获取了getter属性 //return target[key]; } }); console.log(p_obj.name); // undefinedp_obj已经成为了一个Proxy实例,在其handler中我们定义了一个get函数,所以我们获取它的属性时会被拦截,而去触发get函数,return被注释了,所以带出来的值为undefined。
实例方法:
1.get()
get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。
使用get拦截,实现数组读取负数的索引
function createArray (...ele) { let handler = { get(target,key,rec){ let index = Number(key); if(index < 0){ key = String(target.length + index); } return Reflect.get(target,key,rec); } }; let target = []; target.push(...ele); return new Proxy(target,handler); }; let arr = createArray(1,2,3); console.log(arr[-1]); // 32.set()
set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。
使用Proxy的set使属性的值符合条件
let rule = { set: function (obj,prop,value) { if(prop === 'age'){ if(!Number.isInteger(value)){ throw new TypeError('年龄不是整数'); } if(value > 0 && value <= 120){ throw RangeError('年龄必须为0-120之间的整数'); } } obj[prop] = value; } }; let person = new Proxy({},rule); person.age = 18; console.log(person.age); // 18 person.age = '?'; // TypeError person.age = 150; // RangeError3.apply()
apply方法拦截函数的调用、call和apply操作。 apply方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组。
let rule = { apply(target,ctx,args){ return Reflect.apply(...arguments) * 2; } }; function sum (num1,num2) { return num1 + num2; }; var proxy = new Proxy(sum,rule); console.log(proxy(1,2)); // 6 console.log(proxy.call(null,3,4)); // 14 console.log(proxy.apply(null,[5,6])); // 224.has()
has方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符。 has方法可以接受两个参数,分别是目标对象、需查询的属性名。
var handler = { has(target,key){ if(key[0] === '_'){ return false; } return key in target; } }; var target = {_age:58,age:18}; var proxy = new Proxy(target,handler); console.log('_age' in proxy); // false console.log('age' in proxy); // true // has拦截只对in运算符生效,对for...in循环不生效 for(var key in proxy){ console.log(proxy[key]) // 58 18; }