一步一步实现一步一步实现Vue的响应式的响应式(对象观测对象观测)
平时开发中,Vue的响应式系统让我们不再去操作DOM,只需关心数据逻辑的处理,极大地降低了代码的复杂度。而响应式
系统也是Vue的核心,作为开发者有必要了解其实现原理!
简易版简易版
以以watch为切入点为切入点
watch是平时开发中使用率非常高的功能,其目的是观测一个数据,当数据变化时执行我们预先定义的回调。使用方式如下:
{
watch: {
obj(val, oldVal) {
console.log(val, oldVal);
}
}
}
上面观测了Vue实例的obj属性,当其值发生变化时,打印出新值与旧值。
因此,我们定义一个watch函数:
function watch (data, key, cb) {
// do something
}
watch函数接收3个属性,分别是
data: 被观测对象 key: 被观测的属性
cb: 数据变化后要执行的回调
Object.defineProperty
既然要在数据变化后再执行回调,所以需要知道数据是什么时候被修改的,这就是Object.defineProperty的作用,其为数据定
义了访问器属性。在数据被读取时会触发get,在数据被修改时会触发set。
我们定义一个defineReactive函数,其用来将一个数据变成响应式的:
function defineReactive(data, key) {
let val = data[key];
Object.defineProperty(data, key, {
configurable: true,
enumerable: true,
get: function() {
return val;
},
set: function(newVal) {
if (newVal === val) {
return;
}
val = newVal;
}
});
}
defineReactive函数为data对象的key属性定义了get、set,get返回属性key的值val,set中修改key的值为新值newVal。到目
前为止,key属性还是没有什么特殊之处。
数据被修改会触发set,那cb一定是在set中被执行。但set与cb之间好像并没有什么联系,所以我们来搭建一座桥梁,来构建
两者的联系:
let target = null;
我们在全局定义了一个target变量,它用来保存cb的值,然后在set中调用。所以,cb什么时候被保存在target中?回到出发
点,我们要调用watch函数来观测data的key属性,当值被修改时执行我们定义的回调cb,这就是cb被保存在target中的时机
了:
评论0