Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”,即对编程语言进行编程。
讲通俗一点就是扩展(增强)了对象,方法(函数)的一些功能
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。
Proxy其实是设计模式的一种,代理模式
直接通过操作代理对象来操作原对象
new Proxy(target,handle)
参数第一个参数: target 是你要代理的对象
第二个参数,handle是对代理对象做什么操作
{
set(){},
get(){},
deleteProperty(){},
has(){},
apply(),
…
}
返回值返回一个新的对象
let obj = new Proxy(target,handle)
let proxy = new Proxy(target, handler);Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
如果handler没有设置任何拦截,那就等同于直接通向原对象。
var target = {}; var handler = {}; var proxy = new Proxy(target, handler); proxy.a = 'b'; target.a // "b"上面代码中,handler是一个空对象,没有任何拦截效果,访问proxy就等同于访问target。
let obj = { name : 'wuwei' } console.log(obj.name); // 我希望你在获取name 属性的时候做一些事情,那么我们就可以用代理模式 let newObj = new Proxy(obj,{ get(target,property, newObj){ // target就是代理对象obj,property就是用户访问的属性 // console.log(target,property); // {name: "wuwei"} "aaa" console.log(`你访问了${property}属性`) return target[property]; } })例子:创建标签
var proxy = new Proxy({},{ get(target,property){ return function(attr={},...children){ const el = document.createElement(property); // 添加属性 for(let key of Object.keys(attr)){ el[key] = attr[key] } // 添加子元素 for (let child of children){ if(typeof child == 'string'){ child = document.createTextNode(child) } el.appendChild(child) } return el; } } })此时就已经拦截了函数,但是原来的函数却没有执行,
我们通常希望你拦截函数是你拦截的,但是原函数还是要执行,这就需要配合reflect 反射使用
Proxy.revocable方法返回一个可取消的 Proxy 实例。
let target = {}; let handler = {}; let {proxy, revoke} = Proxy.revocable(target, handler); proxy.foo = 123; proxy.foo // 123 revoke(); proxy.foo // TypeError: RevokedProxy.revocable方法返回一个对象,该对象的proxy属性是Proxy实例,revoke属性是一个函数,可以取消Proxy实例。上面代码中,当执行revoke函数之后,再访问Proxy实例,就会抛出一个错误。
Proxy.revocable的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。
如果要增强方法需要跟Reflect配合
我也可以在反射时干些事情
var newFn = new Proxy(fn,{ apply(target,context,args){ // console.log(target,context,args); // console.log(arguments); // console.log(...arguments); return Reflect.apply(...arguments)**3; //反射结果的3次方 } }) console.log(newFn(3,2)); // 125和fn.apply()很相似
Reflect.apply(target,context,args) 有三个参数
target: 需要调用的函数
context: this指向
args : 参数数组
console.log(Math.ceil(4.4)); // 向上取整 5 // 反射调用Math.ceil 没有this指向,传入了null, 参数数组 let num = Reflect.apply(Math.ceil,null,[5.1]); console.log(num); // 6就是调用函数的不同的方式而已
function show(...args){ console.log(this); console.log(args); } // 正常调用 show(1,2,3,4); // this是window, args是[1,2,3,4] // call调用函数 show.call('aaa',1,2,3,4); // this是aaa, args是[1,2,3,4] // apply调用函数 show.apply('aaa',[1,2,3,4]); // this是aaa, args是[1,2,3,4] // reflect.apply调用函数 Reflect.apply(show,'aaa',[1,2,3,4]); // this是aaa, args是[1,2,3,4]通过reflect拿到语言内部的东西
