响应式
- Object.defineProperty
- 观察者模式

流程
- Watcher 和 Dep
- 我们将更新的功能封装了一个 watcher
- 渲染页面前,会将当前 watcher 放到 Dep 类上
- 在 vue 中页面渲染时使用的属性,需要进行依赖收集,收集对象的渲染 watcher
- 取值时,给每个属性都加了个 dep 属性,用于存储这个渲染 watcher(同一个 watcher 会对应多个 dep)
- 每个属性可能对应多个视图(多个视图肯定是多个 watcher),一个属性要对应多个 watcher
- dep.depend() => Dep.target.addDep() => 通知 watcher 存放 dep => dep.addSub() => 通知 dep 存放 watcher
- 双向存储
原理
function Vue(options) {
this._init(options);
}
Vue.prototype._init = function (options) {
const vm = this;
initState(vm);
};
function initState(vm) {
initData(vm);
}
function initData(vm) {
let data = vm.$options.data;
observe(data);
}
function observe(data) {
return new Observer(data);
}
class Observer {
constructor(value) {
if (Array.isArray(value)) {
value.__proto__ = arrayMethods;
this.observeArray(value);
} else {
this.walk(value);
}
}
}
function defineReactive(data, key, value) {
let childOb = observe(value);
let dep = new Dep();
Object.defineProperty(data, key, {
get() {
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
},
set(newValue) {
if (newValue === value) {
return;
}
observe(newValue);
value = newValue;
dep.notify();
},
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
性能
- 嵌套层次不能太深,否则有大量递归
Object.defineProperty
对于不存在的属性不会拦截,也不会响应,可以使用 vm.$set
API 让对象自己去 notify,或者赋予一个新对象- 数组改索引和
length
不触发更新,可以通过 7 个变异方法;数组中如果是对象类型,修改对象可以更新视图