什么是代理?刚开始入行的同学可能就会问了。我们可以这样说,代理Proxy是一个构造函数,它可以接受两个参数:目标对象(target) 与句柄对象(handler) ,返回一个代理对象Proxy,主要用于从外部控制对对象内部的访问。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例
var proxy = new Proxy(target, handler);
对一个空对象架设了一层拦截,重定义了属性的读取(get)和设置(set)行为。
var obj = new Proxy({}, {
get: function (target, propKey, receiver) {
console.log(`getting ${propKey}!`);
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
console.log(`setting ${propKey}!`);
return Reflect.set(target, propKey, value, receiver);
}
});
对设置了拦截行为的对象obj,去读写它的属性,就会得到下面的结果。
obj.count = 1
// setting count!
++obj.count
// getting count!
// setting count!
// 2
每当代理对象被赋值,处理器函数就会调用,这样就可以用来调试某些问题。
当然了,Proxy可不是仅仅为了调试而诞生的,如果你用过Sencha Touch 或者 AngularJS的话,就会发现这些框架都是类似数据模型绑定的功能。
还可以使用proxy来实现多继承。众所周知,JavaScript中每个对象只能有一个直接的上层原型,从而无法实现多继承
apply方法拦截函数的调用、call和apply操作。
var handler = {
apply (target, ctx, args) {
return Reflect.apply(...arguments);
}
};
每当执行proxy函数(直接调用或call和apply调用),就会被apply方法拦截。
var twice = {
apply (target, ctx, args) {
return Reflect.apply(...arguments) * 2;
}
};
function sum (left, right) {
return left + right;
};
var proxy = new Proxy(sum, twice);
proxy(1, 2) // 6
proxy.call(null, 5, 6) // 22
proxy.apply(null, [7, 8]) // 30
在Vue2中双向数据绑定原理(数据劫持)采用Object.defineProperty
,而在Vue3中数据劫持原理采用的是Proxy
代理。
Object.defineProperty
只能劫持对象的属性,不能监听数组。也不能对 es6 新产生的 Map,Set 这些数据结构做出监听。也不能监听新增和删除操作等等。
Proxy
可以直接监听整个对象而非属性,可以监听数组的变化,具有多达13中拦截方法。