响应式
Proxy 和 DefineProperty
我们对一个对象的所有操作,底层都是调用的对象的基本方法,这些基本方法是对象底层调用,外部无法访问。如下示例,而 Proxy 可以用来拦截和重定义这些基本方法
const obj = {};
obj.a = 1; // 属性赋值 [[Set]]
obj.a; // 属性读取 [[Get]]
Object.setPrototypeOf(obj, { a: 3 }); // 设置原型 [[SetPrototypeOf]]
Object.getPrototypeOf(obj); // 读取原型 [[GetPrototypeOf]]
Object.defineProperty(); // 设置属性 [[DefineOwnProperty]]
for (const key in obj) {
} // 遍历属性 [[GetOwnPropertyKeys]]
Proxy
Proxy 对象可以用来拦截和重定义一个对象的所有的基本方法。
const arr = [1, 2, 3];
const proxy = new Proxy(arr, {
get(target, key) {
console.log("get", key);
return target[key];
},
set(target, key, value) {
console.log("set", key, value);
target[key] = value;
return true;
},
});
proxy.push(4);
// get push 读取 push 方法
// get length 读取 length 属性
// set 3 4 设置索引为 3 的值为 4
// set length 4 设置 length 属性为 4
DefineProperty
DefineProperty 只能用来拦截对已有属性的读写,它是对象的基本方法之一。
因此在 Vue2 中需要 $set
$get
这些辅助函数以及重写数组方法来实现一些不太好实现的响应式。比如在 arr.push()
时,想要拦截这个操作,就只能拦截数组长度的变化,但是数组的 length
属性是无法重定义的,也就是拦截不到。
注
Vue2 中改动了数组的原型链,重写了数组方法,来实现响应式。