概述
所谓proxy,字面意义是代理。而有关于代理的名词我们应该听过颇多,例如:代理模式、ip代理等。同时,proxy在Vue,React,Angular等mvvm前端框架的运用中,我们最为耳熟的应该是数据绑定,这使得我们不需要手动进行Dom操作也能实现数据更新。对于ES6中的proxy代理,我们可以简单理解为在目标对象前设置一层拦截,所有外界的访问都必须经过这层拦截,才能对目标对象进行操作,而我们可以在拦截层对操作进行过滤和改写。
Proxy中的劫持操作
对于Proxy中的数据劫持操作,我们使用最多的应该是get和set了。其实除了这两项常用操作,proxy还有一些其他处理方式:
Proxy代理方法——apply
提到apply,想必大家会联想到修改this指向的apply方法。其实,proxy的apply内部实现也蕴含了这样的操作。以下是从最近一次的学习示例中,来聊聊proxy方法代理的apply。
首先,上个栗子!此例本来是想每秒执行一次回调,但是输出结果却不如人愿。
function asyncQue(cb) {
setTimeout(() => {
cb()
},1000)
}
const cb = () => {
let now = new Date().getTime()
console.log(now)
}
asyncQue(cb)
asyncQue(cb)
asyncQue(cb)
接着,借用这个例子来聊聊apply,并捋顺回调执行。既然是代理方法,那么我们先创建一个Proxy对象,而目标对象就是我们的asyncQue方法咯,此时会返回一个代理方法。
剩下的就是恢复目标函数默认行为。怎么恢复呢?我们有和proxy紧密联系的Reflect,通过Reflect的apply静态方法,我们可以完成目标对象的执行。其实,这里的apply确实和修改this指向的apply相像,他接收三个参数,一是要执行的目标对象,二是要绑定的this对象,三是类数组参数。
let promise //全局
let asyncQueProxy = new Proxy(asyncQue,{
apply(target,_this,args) {
promise = Promise.resolve(promise).then(() => {
console.log(target)
// console.log(args)
// .then 返回一个promise
// 上一个promise resolve时,下一个才能执行.then
// Promise.resolve 接收一个promise则返回该promise
return new Promise((resolve,reject) => {
// 恢复他的默认行为
Reflect.apply(target,_this,[() => {
args[0]()
resolve()
}])
})
})
console.log(promise)
}
})
asyncQueProxy(cb)
asyncQueProxy(cb)
asyncQueProxy(cb)
最后,通过代理对象调用结果我们可以看到,三次回调间隔都是1秒。