◆
Vue2 初始化与响应式原理实现流程
- 首先拿到用户传入的 options 然后,赋值给 vue 内部的 $options
- 初始化 state,主要就是拿到 options 中的 data,然后对 data 进行递归 Object.defineProperty 监听
- 在劫持监听之前,需要做一些判断,比如 data 的值是否是对象,是否已经被劫持过
- 如果没有被劫持过,可以增加一个属性标志,等下次使用,判断有没有这个标志,就能知道是否已经被劫持过 ob
- this.walk 中对 data 使用 Object.keys 对对象的 data key 进行劫持
- 修改时,由于属性值被改变,应该重新进行观测
- 用 vm 代理 vm.data
- Obejet.defineproperty 无法监听到数组和对象的内部的变化,所以 vue2.0 重写了常用的数组的方法来使得数组更新的时候触发页面的更新 数组重新定义其原型 'push','pop','shift','unshift','reverse','sort','splice', push unshift splice 新增的值进行劫持观测
- ast -> render->虚拟 dom->真是 dom
- 每个响应式属性都有 dep,dep 存放了依赖这个属性的 watcher(watcher 是观测数据变化的函数),如果数据发生变化,dep 就会通知所有的观察者 watcher 去调用更新方法 观察者需要被目标对象收集,目的是通知依赖它的所有观察者,get 时添加观察者对象,set 时通知更新,循环,触发每一个
- 异步刷新,变量控制,定时器
- vue 通过 MutationObserver 监听 dom 的改变
https://juejin.cn/post/6966418770768166919
function Vue(options) {
// options就是用户的选项
this._init(options); // 默认就调用了init
}
import { newArrayProto } from './array';
function proxy(vm, target, key) {
Object.defineProperty(vm, key, {
// vm.name
get() {
return vm[target][key]; // vm._data.name
},
set(newValue) {
vm[target][key] = newValue;
},
});
}
function initData(vm) {
let data = vm.$options.data; // data可能是函数和对象
data = typeof data === 'function' ? data.call(vm) : data; // data是用户返回的对象
vm._data = data; // 我将返回的对象放到了_data上
// 对数据进行劫持 vue2 里采用了一个api defineProperty
observe(data);
// 将vm._data 用vm来代理就可以了
for (let key in data) {
proxy(vm, '_data', key);
}
}
class Observer {
constructor(data) {
// Object.defineProperty只能劫持已经存在的属性 (vue里面会为此单独写一些api $set $delete)
Object.defineProperty(data, '__ob__', {
value: this,
enumerable: false, // 将__ob__ 变成不可枚举 (循环的时候无法获取到)
});
// data.__ob__ = this; // 给数据加了一个标识 如果数据上有__ob__ 则说明这个属性被观测过了
if (Array.isArray(data)) {
// 这里我们可以重写数组中的方法 7个变异方法 是可以修改数组本身的
data.__proto__ = newArrayProto; // 需要保留数组原有的特性,并且可以重写部分方法
this.observeArray(data); // 如果数组中放的是对象 可以监控到对象的变化
} else {
this.walk(data);
}
}
walk(data) {
// 循环对象 对属性依次劫持
// "重新定义"属性 性能差
Object.keys(data).forEach(key => defineReactive(data, key, data[key]));
}
observeArray(data) {
// 观测数组
data.forEach(item => observe(item));
}
}
export function defineReactive(target, key, value) {
// 闭包 属性劫持
observe(value); // 对所有的对象都进行属性劫持
Object.defineProperty(target, key, {
get() {
// 取值的时候 会执行get
console.log('key', key);
return value;
},
set(newValue) {
// 修改的时候 会执行set
if (newValue === value) return;
observe(newValue);
value = newValue;
},
});
}
export function observe(data) {
// 对这个对象进行劫持
if (typeof data !== 'object' || data == null) {
return; // 只对对象进行劫持
}
if (data.__ob__ instanceof Observer) {
// 说明这个对象被代理过了
return data.__ob__;
}
// 如果一个对象被劫持过了,那就不需要再被劫持了 (要判断一个对象是否被劫持过,可以增添一个实例,用实例来判断是否被劫持过)
return new Observer(data);
}

还没有留言,来发表第一条吧~