什么是数据响应式?
Vue.js文档 中这样说: Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。这使得状态管理非常简单直接。
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
Object.defineProperty() 的用法:
let data2 = {}
data2._n = 0 // _n 用来偷偷存储 n 的值
Object.defineProperty(data2, 'n', {
get(){
return this._n
},
set(value){
if(value < 0) return
this._n = value
}
})
Object.defineProperty() 可以给对象添加属性value,可以给对象添加 getter/setter, getter/setter 用于对属性的读写进行监控。
但是这里有一个问题是,我们可以通过修改变量 data2._n 来改变里面的值,为了解决这个问题,需要使用代理:
let data3 = proxy({ data:{n:0} }) // 括号里是匿名对象,无法访问
function proxy({data} /* 解构赋值*/){
const obj = {}
Object.defineProperty(obj, 'n', {
get(){
return data.n
},
set(value){
if(value<0)return
data.n = value
}
})
return obj // obj 就是代理
}
但上面的代码还可以通过下面的方式来修改:
let myData = {n:0}
let data4 = proxy({ data:myData })
为了解决这样的问题,还需要添加监听:
let myData5 = {n:0}
let data5 = proxy2({ data:myData5 })
function proxy2({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(value<0)return
data.n = value
}
})
return obj // obj 就是代理
}
以上大概就是 Vue 实现数据响应式的原理。
vm = new Vue({data:myData})
一、会让 vm 成为 myData 的代理(proxy)
二、会对 myData 的所有属性进行监控
当 vm 监控到 myData 的属性发生变化,就可以调用 render(data) 来更新视图。