一、原理 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文档