赞
踩
首先proxy的英文意思的代理,proxy用自己的话理解的话就是一个拦截器或者是过滤器
感觉本质上就是在被代理的目标对象上加了一些事件行为
const p = new Proxy(target, handler)
参数
let obj = {
a:5
}
const proxyObj = new Proxy(obj,{
get:function(){
return 'proxy'
},
set:function(){
}
})
console.log(obj.a);
console.log(proxyObj.a);
Proxy 实例也可以作为其他对象的原型对象。
const proxyObj = new Proxy(obj,{ get:function(target,attr){ return target[attr] }, set:function(){ } }) console.log(obj.a); console.log(proxyObj.a); // class Ctx1{ // } function Ctx(){ } console.log(Ctx.prototype,Ctx1.prototype); Ctx.prototype = Object.create(proxyObj) let x = new Ctx() console.log(x.a);
handler.get() 方法用于拦截对象的读取属性操作。
语法
var p = new Proxy(target, {
get: function(target, property, receiver) {
}
});
get方法可以返回任何值。
拦截
该方法会拦截目标对象的以下操作:
const obj = { attr:'property', void:'method' } const proxyObj = new Proxy(obj,{ get:function(target,prop){ if(prop in target){ // 有这个属性就返回 return target[prop] }else{ // 没有这个属性就报错 console.log(target); throw ReferenceError(`${prop} is not exsit in target object`) } } }) console.log(proxyObj.attr ); console.log(proxyObj.void); console.log(proxyObj.a);
get的第三个对象
第三个对象就是返回当前调用的proxy实例
const proxy = new Proxy({},{
get(target,prop,receiver){
return receiver
}
})
console.log(proxy.getReceiver === proxy);//true
andler.set() 方法是设置属性值操作的捕获器。
语法
const p = new Proxy(target, {
set: function(target, property, value, receiver) {
}
});
以下是传递给 set() 方法的参数。this 绑定在 handler 对象上。
let validator = { set(target,prop,val){ if(prop === 'age'){ if(!Number.isInteger(val)){ throw new TypeError('The age is not ange integer') } if(val>200){ throw new RangeError('The age is invalid') } } target[prop] = val } } let person = new Proxy({},validator) person.age = 100 console.log(person.age); person.age = 2.2 person.age = 22222
注意,严格模式下,set代理如果没有返回true,就会报错。
用ES5的Object.defineProperty实现get和set的拦截也是可以的,但是由于此方法开始时是针对某个属性来设置的,所以需要一些操作,有点麻烦
// 用ES5的Object.defineProperty实现get的拦截 比较麻烦 const obj = { one: 1, two: 2, three: 3 } for (var key in obj) { let val = obj[key] Object.defineProperty(obj, key, { get() { return val } }) } console.log(obj.one); //1
function judgeMent(prop,action){ if(prop[0] === '_'){ throw new Error(`Invalid attempt to ${action} private "${prop}" property`) } } const handler = { get(target,prop){ judgeMent(prop,'get') return target[prop] }, set(target,prop){ judgeMent(prop,'set') return true } } const proxyObj =new Proxy({_name:"Bob"},handler) // proxyObj._name proxyObj._age = 18
handler.apply() 方法用于拦截函数的调用,可以返回任何值
function sum(a, b) { return a + b; } const handler = { apply: function(target, thisArg, argumentsList) { console.log(`Calculate sum: ${argumentsList}`); // expected output: "Calculate sum: 1,2" return target(argumentsList[0], argumentsList[1]) * 10; } }; const proxy1 = new Proxy(sum, handler); console.log(sum(1, 2)); // expected output: 3 console.log(proxy1(1, 2)); // expected output: 30
has方法用来拦截hasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符。( 但是对for in的操作不起作用 )
== handler.has() 方法是针对 in 操作符的代理方法。==
const handler = { has(target,prop){ if(prop[0] === '_'){ return false } return prop in target } } const target = { _secret:'easily scared', eyeCount:4 } const proxyObj = new Proxy(target,handler) console.log('eyeCount' in proxyObj); console.log('_secret' in proxyObj);
construct方法用于拦截new命令
construct方法返回的必须是一个对象,否则会报错。
function monster1(disposition) { this.disposition = disposition; } const handler1 = { construct(target, args) { console.log('monster1 constructor called'); // expected output: "monster1 constructor called" return new target(...args); } }; const proxy1 = new Proxy(monster1, handler1); console.log(new proxy1('fierce').disposition); // expected output: "fierce"
还有一些不常用的方法请参照MDN
在 Proxy 代理的情况下,目标对象内部的this关键字会指向 Proxy 代理。
上面代码中,一旦proxy代理target.m,后者内部的this就是指向proxy,而不是target。
上面代码中,目标对象jane的name属性,实际保存在外部WeakMap对象_name上面,通过this键区分。由于通过proxy.name访问时,this指向proxy,导致无法取到值,所以返回undefined。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>proxy实现双向绑定</title> </head> <body> <input type="text" id="input"/> <h1 id="h1"></h1> <script> let inp = document.querySelector('#input') let h1 = document.querySelector('#h1') let obj = { val:'1123' } let proxyObj = new Proxy(obj,{ set(target,attr,value){ target[attr] = value inp.value = value h1.innerHTML = value } }) proxyObj.val = obj.val //实现set,使输入框和p标签都显示obj.val值 inp.addEventListener('input',function(){ console.log(inp.value); proxyObj.val = inp.value //数据同时变化 }) </script> </body> </html>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。