👉 数据响应式
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty
把这些 property 全部转为 getter/setter。Object.defineProperty
是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
👉 语法
Object.defineProperty(obj, prop, descriptor)
查看更多
- obj: 要定义属性的对象。
- prop: 要定义或修改的属性的名称或 Symbol 。
- descriptor: 要定义或修改的属性描述符。
共享以下可选键值:
configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
默认为 false。
enumerable
当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
默认为 false。
数据描述符还具有以下可选键值:
value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
默认为 undefined。writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。
默认为 false。
👉 实践
<div id="app">
hello
</div>
// 模拟 Vue 中的 data 选项
let data = {
msg: 'hello'
}
// 模拟 Vue 的实例
let vm = {}
// 数据劫持:当访问或者设置 vm 中的成员的时候,做一些干预操作
Object.defineProperty(vm, 'msg', {
enumerable: true,
configurable: true,
get () {
console.log('get: ', data.msg)
return data.msg
},
set (newValue) {
console.log('set: ', newValue)
if (newValue === data.msg) {
return
}
data.msg = newValue
// 数据更改,更新 DOM 的值
document.querySelector('#app').textContent = data.msg
}
})
vm.msg = 'Hello World'
console.log(vm.msg)
// set: Hello World
// get: Hello World
// Hello World
那假设是有多属性的对象呢?需要如何绑定。
核心思路就是递归遍历对象,将对象内的所有属性都绑定。
let data = {
msg: 'hello',
age: 18
}
let vm = {}
proxyData(data)
function proxyData(data){
Object.keys(data).forEach(key => {
// 把 data 中的属性,转换成 vm 的 setter/setter
Object.defineProperty(vm, key, {
enumerable: true,
configurable: true,
get () {
console.log('get: ', key, data[key])
return data[key]
},
set (newValue) {
console.log('set: ', key, newValue)
if (newValue === data[key]) {
return
}
data[key] = newValue
// 数据更改,更新 DOM 的值
document.querySelector('#app').textContent = data[key]
}
})
})
}
简单了解数据劫持后,我们来看看完整流程。Vue初始的时候,将data中的数据通过 Observe 数据劫持
后,将数据利用观察者模式来监控,当事件触发时,通过 发布者Dep
去调用 观察者Watcher
的方法来更新视图。
了解大致流程后,我们从基础出发,理解Vue中的设计模式: 发布/订阅模式
和 观察者模式
。后面会针对这两点继续深入。