Vue响应式原理

一、原理

Vue会遍历data对象的所有property,并使用Object.defineProperty把这些property全部转为getter/setter。通过getter/setter让 Vue 能够追踪依赖,在property被访问和修改时通知变更。

二、Object.defineProperty 和 getter、setter

Object.defineProperty方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

1
2
3
4
5
 let data1 = {};
Object.defineProperty(data1, "n", {
value: 0
});
console.log(data1.n); //0

getter/setter用于对属性的读写进行监控

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
let myData2 = { n: 0 };
let data2 = proxy({ data: myData2 }); // 括号里是匿名对象,无法访问

function proxy({ data }) {
let value = data.n;
Object.defineProperty(data, "n", {
get() {
return value;
},
set(newValue) {
if (newValue < 0) return;
value = newValue;
}
});
//监听 data

const obj = {};
Object.defineProperty(obj, "n", {
get() {
return data.n;
},
set(value) {
if (newValue < 0) return;
data.n = value;
}
});
return obj; // obj 就是代理
}

console.log(data2.n); //0
myData2.n = -1;
console.log(data2.n); //0
myData2.n = 1;
console.log(data2.n); //1

let vm=new Vue({data:myData})时,会让 vm 成为 Vue 的代理,对 myData 的所有属性进行监控,使得 myData 的属性变化的时候渲染页面。

三、总结

Vue 的数据响应式,是通过Object.defineProperty将对象所有的属性转化为getter/setter来监控数据变化,即时渲染页面。

注意:Vue 不能检测到对象属性的添加或删除,解决方法是手动调用 Vue.set 或者 this.$set
文档