认识 Proxy()
Proxy
是ES6
新增的构造函数,主要目的是给对象中间增加了一层代理(拦截)。
形象的比喻:
Proxy
就是明星的经纪人,如果你想和明星谈业务必须通过经纪人来操作
var proxy = new Proxy();
Proxy
和Object.defineProperty()
劫持数据有点类似,但又有区别:
Object.defineProperty()
主要劫持数据,给对象进行拓展,对属性进行设置。Proxy
返回一个代理对象,并不是数据劫持,通过处理目标对象后返回一个代理对象,通过操作代理对象中途可以做一些额外的操作,然后再操作实际对象
总结:Proxy
的核心是怎么处理属性,defineProperty()
方法的核心是怎么定义属性。
Proxy
接收两个参数:
target
要处理的对象handler
处理程序对象handler
内部有非常多的方法,本文只简单的介绍set
和get
方法(相关链接)
var obj = {
a: 1,
b: 2
};
var proxy = new Proxy(obj, {
// get() 有两个参数,目标对象和属性值
get(target, prop) {
console.log("This is property value " + target[prop]);
return target[prop];
},
// set 有三个参数,目标对象、属性值和新值
set(target, prop, newVal) {
target[prop] = newVal;
},
});
console.log(obj); // {a:1, b:2}
console.log(proxy); // Proxy{a:1, b:2}
console.log(proxy.a);
// 访问属性 a,打印以下内容:
// This is property value 1
// 1
// 设置属性 a
proxy.b = 3;
console.log(obj); // {a: 1, b: 3}
console.log(proxy); // Proxy {a: 1, b: 3}
Proxy
还可以处理其他的数据类型。
1、处理Array
var arr = [
{ name: "小明", age: 18 },
{ name: "小红", age: 19 },
{ name: "小王", age: 20 },
];
var persons = new Proxy(arr, {
get(target, prop) {
return target[prop];
},
set(target, prop, newVal) {
target[prop] = newVal;
},
});
console.log(persons[0]); // {name: '小明', age: 18}
persons[0] = { name: "小张", age: 33 };
console.log(persons); // Proxy {0: {…}, 1: {…}, 2: {…}}
console.log(arr); // [{"name":"小张","age":33},{"name":"小红","age":19},{"name":"小王","age":20}]
2、处理函数
var fn = function () {
console.log("I am a function.");
};
fn.a = 123;
var newFn = new Proxy(fn, {
get(target, prop) {
return target[prop];
},
set() {},
});
console.log(newFn); // Proxy {a: 123, length: 0, name: 'fn', arguments: null, caller: null, …}
console.log(newFn.a) // 123
Proxy() VS defineProperty()
当Proxy()
的内部处理对象方法去操作target
对象 (调用proxy
的方法)的时候实际操作的仍然是target
对象的方法,handler
内的方法可以重写target
内任何方法,因此来达到代理拦截的目的。
Object.defineProperty()
和Proxy()
都可以达到拦截数据的目的
但是Object.defineProperty()
原则本身是给对象定义属性用的,所以当Array
的push
和pop
等方法是无法触发setter
机制的,改变数组长度、用数组的下标设置值的时候可以触发。
那么vue2.x
是怎么用Object.defineProperty()
做的?vue2.x
是把数组相关方法全部重写,所以才导致大量的代码显得非常臃肿。
为什么vue2
没有使用Proxy()
?
因为ES6
当时兼容不太好,而在现在ES6
大量使用,所以vue3
用Proxy()
重写了!
而Proxy()
没有这个问题,它是通过代理去操作原始数据,而defineProperty()
是对原对象操作的时候进行拦截。
Reflect
Reflect
是一个对象,可以用于操作目标对象的行为,它是定义的内置对象,是方法集合的容器。Reflect
与Object
类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与Proxy
是对应的。
举例 🌰:
var obj = { a: 1, b: 2 };
var proxy = new Proxy(obj, {
get: function (target, prop) {
// return target[prop];
// 用 Reflect 代替
return Reflect.get(target, prop);
},
set: function (target, prop, newVal) {
const isOk = Reflect.set(target, prop, newVal);
if (isOk) {
console.log("SET successfully");
}
},
});
proxy.c = 3;
console.log(proxy);
:::danger
Reflect
的好处JS
中好多方法都存在Object.prototype.constructor
(因为都是静态方法)Reflect
相当于一个的方法容器,ECMA
规定未来很有很多方法都放到Reflect
上而不是Object
上JS
对Object
的定义非常的混乱,object
是广义的对象(一切皆对象),Object
是狭义的对象Object
存在很多共用的方法,这样很多时候都觉得不太合理,这个时候就产生了Reflect
来存储方Reflect
是ES6
的全局的内置对象
:::