ES6 Proxy代理
概述
Proxy代理 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式。
基本用法
Proxy代理
一个 Proxy 对象由两个部分组成: target 、 handler 。在通过 Proxy 构造函数生成实例对象时,需要提供这两个参数。 target 即目标对象, handler 是一个对象,声明了代理 target 的指定行为。
let target = { // target 可以为空对象,调用 set 方法,向目标对象中添加了 属性 name: 'Tom', age: 24 } let handler = { get: function(target, key) { console.log('getting '+key); return target[key]; // 不是target.key }, set: function(target, key, value) { console.log('setting '+key); target[key] = value;
return true; //严格模式下,set代理如果没有返回true,就会报错。 } } let proxy = new Proxy(target, handler) proxy.name // 实际执行 handler.get proxy.age = 25 // 实际执行 handler.set
实例方法
1、get(target, propKey, receiver) 用于拦截某个属性的读取(read)操作,就是在读取目标对象的属性之前,搞点事情。
参数:
target:目标对象
property:属性名
receiver:操作行为所针对的对象,一般指proxy实例本身
let exam={};
let proxy = new Proxy(exam, { get(target, propKey, receiver) { console.log('Getting ' + propKey); return target[propKey]; } })
console.log(proxy.name);//undefined
2、set(target, propKey, value, receiver) 用来拦截目标对象的赋值(write)操作
参数:
target:目标对象
propertyName:属性名
propertyValue:属性值
receiver:Proxy实例本身
let validator = { set: function(obj, prop, value) { if (prop === 'age') { if (!Number.isInteger(value)) { throw new TypeError('The age is not an integer'); return false; } if (value > 200) { throw new RangeError('The age seems invalid'); return false; } } // 对于满足条件的 age 属性以及其他属性,直接保存 obj[prop] = value; return true; } }; let proxy= new Proxy({}, validator) proxy.age = 100; proxy.age // 100 proxy.age = 'oppps' // 报错 proxy.age = 300 // 报错
3、apply(target, ctx, args) 用于拦截函数的调用、call 和 reply 操作。
target 表示目标对象,
ctx 表示目标对象上下文,
args 表示目标对象的参数数组。
function sub(a, b){ return a - b; } let handler = { apply: function(target, ctx, args){ console.log('handle apply'); return Reflect.apply(...arguments); } } let proxy = new Proxy(sub, handler) proxy(2, 1) // 1
4、has(target,propkey) 拦截 propKey in proxy 的操作,返回一个布尔值。即在判断 target 对象是否存在 propKey 属性时,会被这个方法拦截。
let proxy = new Proxy(exam, handler) 'name' in proxy
5、deleteProperty(target, propKey) 拦截delete proxy[propKey]
的操作,返回一个布尔值。用于拦截 delete 操作。如下是删除实例:
var handler = { deleteProperty(target,key){ console.log('key',key); invariant(key,'delete'); delete target[key]; return true; } }; function invariant (key,action) { if(key[0] === '_') { throw new Error(`Invalid attempt to ${action} private "${key}" property`); return false; } } var target = {_prop:'foo',prop:'foo'}; var proxy = new Proxy(target,handler); console.log("target1",target);//target1 {_prop: "foo", prop: "foo"} console.log("delete1",delete proxy.prop);//key prop delete1 true console.log("target2",target);//target2 {_prop: "foo"} console.log("deletetarget",delete target._prop);//deletetarget true 直接删除 console.log("target3",target);//target3 {} console.log("delete2",delete proxy._prop);//key _prop Uncaught Error: Invalid attempt to delete private "_prop" property 通过代理则删除失败
6、construct(target, args) 用于拦截 new 命令。返回值必须为对象。
7、ownKeys(target) 用于拦截对象自身属性的读取操作。
8、getPrototypeOf(target) 拦截对象原型操作
9、isExtensible(target) 用于拦截 Object.isExtensible 操作。
扩展:
JavaScript中,对象的extensible属性用于表示是否允许在对象中动态添加新的property。ECMAScript 3标准中,所有的对象都是extensible的。ECMAScript 5标准中,所有的对象默认仍是extensible的,但可以通过设定来改变这一属性。查询一个对象是否是extensible的,可以使用Object.isExtensible()语句:
……