vue怎样实现mvvm
Vue 的 MVVM 实现原理
Vue 通过数据绑定和响应式系统实现 MVVM(Model-View-ViewModel)模式,核心是数据驱动视图更新。
数据劫持(Observer)
Vue 使用 Object.defineProperty 或 Proxy 劫持数据对象的属性,在属性被访问或修改时触发依赖收集和更新。

// 简化版数据劫持
function defineReactive(obj, key) {
let value = obj[key]
Object.defineProperty(obj, key, {
get() {
console.log('收集依赖')
return value
},
set(newVal) {
if (newVal !== value) {
console.log('触发更新')
value = newVal
}
}
})
}
依赖收集(Dep)
每个被劫持的属性都有一个 Dep 实例,用于管理所有依赖该属性的 Watcher。
class Dep {
constructor() {
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
notify() {
this.subs.forEach(sub => sub.update())
}
}
观察者(Watcher)
Watcher 是视图和数据的桥梁,在数据变化时触发视图更新。

class Watcher {
constructor(vm, exp, cb) {
this.vm = vm
this.exp = exp
this.cb = cb
this.value = this.get()
}
get() {
Dep.target = this
let value = this.vm[this.exp]
Dep.target = null
return value
}
update() {
const newValue = this.vm[this.exp]
if (newValue !== this.value) {
this.value = newValue
this.cb.call(this.vm, newValue)
}
}
}
模板编译(Compiler)
Vue 将模板编译为渲染函数,解析指令和插值表达式,创建对应的 Watcher。
// 简化的文本节点编译
function compileText(node, vm) {
const reg = /\{\{(.*)\}\}/
if (reg.test(node.textContent)) {
const exp = RegExp.$1.trim()
new Watcher(vm, exp, function(value) {
node.textContent = value
})
node.textContent = vm[exp]
}
}
响应式流程
- 初始化时劫持数据属性
- 编译模板时遇到数据绑定创建
Watcher Watcher读取数据触发getter,Dep收集依赖- 数据变化时触发
setter,Dep通知所有Watcher更新 Watcher执行回调更新视图
实现示例
class Vue {
constructor(options) {
this.$options = options
this._data = options.data
this.observe(this._data)
this.compile()
}
observe(data) {
Object.keys(data).forEach(key => {
defineReactive(data, key)
})
}
compile() {
const el = document.querySelector(this.$options.el)
this.compileNode(el)
}
compileNode(node) {
if (node.nodeType === 1) {
// 元素节点处理指令
} else if (node.nodeType === 3) {
// 文本节点处理插值
compileText(node, this)
}
}
}
现代 Vue 的优化
Vue 3 改用 Proxy 实现响应式,解决了 Object.defineProperty 的局限性:
- 无法检测新增/删除属性
- 数组变异方法需要特殊处理
- 性能更好
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key)
return Reflect.get(target, key)
},
set(target, key, value) {
const result = Reflect.set(target, key, value)
trigger(target, key)
return result
}
})
}






