02响应式系统基本原理
响应式系统
Vue.js是一款MVVM框架,数据模型如果仅仅是普通的JS对象,但是对这些对象进行操作时,却能影响对应视图,它的核心实现就是[响应式系统]。尽管我们在使用Vue开发时不会直接修改响应式系统,但是理解它的实现有助于是避开一些常见的坑。也有助于预见一些琢磨不透的问题时可以深入其原理来解决它。
Object.defineProperty
首先来介绍一下 Object.defineProperty,Vue就是基于它实现了响应式系统的。
更多参考mdn文档
实现 observer
我们用它来使对象变成可观察的。 这一部分的内容之前提到过,在_init阶段会进行初始化,对数据进行响应式化。
为便于理解,我们不考虑数组等复杂情况,只对对象进行处理。首先定义一个cb函数,该函数用于模拟视图更新,调用它即代表更新视图,内部可以是一些更新视图的方法。
function cb(val) {
/* 渲染视图 */
}然后定义一个defineReactive,该方法通过Object.defineProperty来实现对对象的响应式化。入参是一个obj(需要绑定的对象)、key(obj的某一属性)和val(具体值)。经过defineReactive处理后,我们的obj的key在读取时会触发reactiveGetter方法,而该属性被写入时会触发reactiveSetter方法。
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true, // 属性可枚举
configurable: true, // 属性可被修改或删除
get: function reactiveGetter() {
return val // 会进行依赖收集
},
set: function reactiveSetter(newVal) {
if (newVal === val) return
cb(newVal)
}
})
}当然这是不够的,我们需要在上面再封装一层observer。该函数传入一个value(需要响应化的对象),通过遍历所有属性的方式对该对象的每一个属性都通过defineReactive来处理。
function observer(needReactiveObj) {
if (!needReactiveObj || typeof needReactiveObj !== 'object') return
Object.keys(needReactiveObj).forEach(key => {
defineReactive(needReactiveObj, key, needReactiveObj[key])
})
}最后,让我们用observer来封装一个Vue对象吧
在Vue的构造函数中,对options的data进行处理,这里的data就是我们平时在组件里所写的data属性(实际上就是一个函数,这里当作一个对象来简单处理)
class Vue {// Vue构造类
constructor(options) {
this._data = options.data
observer(this._data)
}
}这样我们只需要new一个Vue对象,就会将data中的数据进行响应式化,如果我们对data的属性进行下面操作,就会触发cb方法更新视图
let vm = new Vue({
data: {
text: 'hello vue'
}
})
vm._data.text = 'vue is wonderful!' // 视图自动更新至此,Vue的响应式原理介绍完毕。接下来我们继续学习响应式系统的另一部分——依赖收集.
注:本节代码参考《响应式系统的基本原理》。
