最近在使用Mobx,对Mobx很喜欢,想仔细学习Mobx响应原理。它是通过Proxy来实现响应的。我先学一下Proxy
Proxy 的作用
就像python里的@property, Proxy可以让拦截外界对对象的属性的读写。在此时,调用某个自定义函数。这样可以让对象感知外界对自身属性的访问或者自身属性的变化。一般在前端库里使用,例如Mobx, vue3,等,来实现状态的响应式更新。
Proxy 的使用
它有两个参数
- target: Object 目标对象
- handler: 外界对对象进行操作时的回调函数, MDN文档里称之为trap
最简单的情形:handler为空对象
const target = {
message1: "hello",
message2: "everyone",
};
const handler = {};
const proxy = new Proxy(target, handler);
console.log(proxy);
console.log(proxy.message1);
console.log(proxy.message2);
➜ learn-js ts-node main.ts
{ message1: 'hello', message2: 'everyone' }
hello
everyone
此时proxy看起来和原来的对象没有什么不同。只看输出,看不出来这是非proxy。但把以上代码放在浏览器里,可以看出proxy的类型是Proxy。
get trap
const proxy = new Proxy(target, {
get: (target, prop, receiver) => {
if (prop === "message2") {
return "world";
}
return Reflect.get(target, prop, receiver);
}
});
console.log(proxy.message1);
console.log(proxy.message2);
➜ learn-js ts-node main.ts
hello
world
代码改成以上形式。get trap中,target是原始对象,prop是属性名,receiver不知道什么东西,暂时用不到。Reflect.get类似.运算符一样。MDN文档里表示,在这里如果直接使用.运算符,又让这个trap拦截了,可能导致无限递归。但我没遇到这个问题。
看打印出来的proxy.message2的值为"world",证明拦截成功。
set trap
const proxy = new Proxy(target, {
set(target, property, value, receiver) {
console.log(property, value);
target[property] = value;
return true;
}
});
proxy.message1 = "hi";
console.log(proxy.message1);
➜ learn-js ts-node -T main.ts
message1 hi
hi
set trap中,target是原始对象,property/value分别是要设置的属性名/值,receiver不知道是什么。从打印出的内容可以看出,set trap运行了。 注意set trap如果返回false则会报错。一般情况下应该返回true。
总结
先看这些吧,光是这两个trap,应该就能实现响应式状态更新了。