Vue的基本原理
-
当一个Vue实例被创建的时候,Vue会遍历data中的属性
-
用Object.defineProperty劫持data的每个属性并且赋予getter和setter
-
同时在内部追踪相关依赖,当访问属性和修改属性的时候会通知变化
-
每个组件实例都会有一个watcher程序实例,他会在组件渲染的过程中国把属性记录为依赖 之后当setter调用的时候会通知watcher重新计算 从而使它关联的组件实现更新
Vue双向绑定的基本原理步骤
-
使用observe对象来观测值的变化(源码如下)
class Observer {
// 观测值
constructor(value) {
this.walk(value);
}
walk(data) {
// 对对象上的所有属性依次进行遍历观测
let keys = Object.keys(data);
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
let value = data[key];
defineReactive(data, key, value);
}
}
}
function defineReactive(data, key, value) {
// 思考?如果Vue数据嵌套层级过深 >>性能会受影响
observe(data) 递归的关键 如果对象是个嵌套对象还会重新new Observe 从新走一遍defineReactive
//使用object.defineProperty 对data的每个属性进行劫持赋予get set从而实现页面更新
Object.defineProperty(data, key, {
get() {
console.log("访问值");
return value;
},
set(newValue) {
if (newValue === value) return;
console.log("更改值");
value = newValue;
},
});
}
-
当data 是一层对象又嵌套一层对象的时候,例如:a:{ b:{1}}
这时候就需要observe对象进行递归遍历 从而使子对象都加上setter和getter来达到数据变化
export function observe(value) {
// 如果传过来的是对象或者数组 进行属性劫持
if (
Object.prototype.toString.call(value) === "[object Object]" ||
Array.isArray(value)
) {
return new Observer(value); // 递归的关键 重新走一遍 definReactive方法
}
}
思考这样的劫持方式对数组有什么影响
这样的方式数组或者对象都可以进行监测,像声明一个数组a:[1,2,3,4,5,6],我们可以通过下标直接修改胡数据也可以触发set,但是当数组中的元素数量可多的时候,就需要给每个元素都加上set,get,这样必然会对性能产生影响,所以这种方式只适合和劫持对象
所以劫持数组的话 就需要使用 数组的方法进行比如说 push unshift 等等
Object.defineProperty 缺点?
对象新增的属性和删除的属性 set都检测不到 之后对象本身的属性才可以被劫持
只能检测到对象的具体某一个属性 (Vue3用了proxy代理)
后续需要Watcher 配合 Observe 和Compile进行试图更新