
Mvvm(入口文件) 的实现
一般会这样调用 Mvvm 框架
const vm = new Mvvm({
el: '#app',
data: {
title: 'mvvm title',
name: 'mvvm name'
},
})
但是这样子的话,如果要得到 title 属性就要形如 vm.data.title 这样取得,为了让 vm.title 就能获得 title 属性,从而在 Mvvm 的 prototype 上加上一个代理方法,代码如下:
function Mvvm (options) {
this.data = options.data
const self = this
Object.keys(this.data).forEach(key =>
self.proxyKeys(key)
)
}
Mvvm.prototype = {
proxyKeys: function(key) {
const self = this
Object.defineProperty(this, key, {
get: function () { // 这里的 get 和 set 实现了 vm.data.title 和 vm.title 的值同步
return self.data[key]
},
set: function (newValue) {
self.data[key] = newValue
}
})
}
}
实现了代理方法后,就步入主流程的实现
function Mvvm (options) {
this.data = options.data
// ...
observe(this.data)
new Compile(options.el, this)
}
observer(观察者) 的实现
observer 的职责是监听 Model(JS 对象) 的变化,最核心的部分就是用到了 Object.defineProperty() 的 get 和 set 方法,当要获取 Model(JS 对象) 的值时,会自动调用 get 方法;当改动了 Model(JS 对象) 的值时,会自动调用 set 方法;从而实现了对数据的劫持,代码如下所示。
let data = {
number: 0
}
observe(data)
data.number = 1 // 值发生变化
function observe(data) {
if (!data || typeof(data) !== 'object') {
return
}
const self = this
Object.keys(data).forEach(key =>
self.defineReactive(data, key, data[key])
)
}
function defineReactive(data, key, value) {
observe(value) // 遍历嵌套对象
Object.defineProperty(data, key, {
get: function() {
return value
},
set: function(newValue) {
if (value !== newValue) {
console.log('值发生变化', 'newValue:' + newValue + ' ' + 'oldValue:' + value)
value = newValue
}
}
})
}
运行代码,可以看到控制台输出 值发生变化 newValue:1 oldValue:0,至此就完成了 observer 的逻辑。
Dep(订阅者数组) 和 watcher(订阅者) 的关系
观测到变化后,我们总要通知给特定的人群,让他们做出相应的处理吧。为了更方便地理解,我们可以把订阅当成是订阅了一个微信公众号,当微信公众号的内容有更新时,那么它会把内容推送(update) 到订阅了它的人。

