实现vue双向绑定

Vue双向绑定的实现原理
Vue的双向绑定主要通过数据劫持结合发布-订阅模式实现。核心是利用Object.defineProperty()或ES6的Proxy来劫持各个属性的getter和setter,在数据变动时发布消息给订阅者,触发相应的监听回调。
基于Object.defineProperty的实现
// 数据监听器
function observe(data) {
if (!data || typeof data !== 'object') return
Object.keys(data).forEach(key => {
defineReactive(data, key, data[key])
})
}
function defineReactive(obj, key, val) {
observe(val) // 递归监听子属性
const dep = new Dep() // 每个属性都有独立的Dep实例
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
Dep.target && dep.addSub(Dep.target) // 收集依赖
return val
},
set(newVal) {
if (newVal === val) return
val = newVal
dep.notify() // 通知所有订阅者
}
})
}
// 依赖收集器
class Dep {
constructor() {
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
notify() {
this.subs.forEach(sub => sub.update())
}
}
// 订阅者
class Watcher {
constructor(vm, exp, cb) {
this.vm = vm
this.exp = exp
this.cb = cb
this.value = this.get() // 触发getter添加自己到dep
}
get() {
Dep.target = this
const value = this.vm.data[this.exp] // 触发getter
Dep.target = null
return value
}
update() {
const newVal = this.vm.data[this.exp]
if (this.value !== newVal) {
this.value = newVal
this.cb.call(this.vm, newVal)
}
}
}
基于Proxy的实现(Vue 3.x)
function reactive(obj) {
const handler = {
get(target, key, receiver) {
track(target, key)
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver)
trigger(target, key)
return true
}
}
return new Proxy(obj, handler)
}
const targetMap = new WeakMap()
function track(target, key) {
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = new Set()))
}
dep.add(activeEffect)
}
function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const effects = depsMap.get(key)
effects && effects.forEach(effect => effect())
}
模板编译过程
- 解析模板生成AST语法树
- 优化AST(标记静态节点)
- 生成渲染函数
- 创建Watcher实例,在数据变化时执行更新
双向绑定的完整流程
初始化时通过observe()递归遍历data对象
为每个属性创建Dep实例作为依赖收集器
编译模板时遇到指令如v-model创建Watcher
Watcher在初始化时触发属性的getter被添加到Dep
数据变化时触发setter,Dep通知所有Watcher更新
Watcher更新触发组件重新渲染
常见指令实现示例
// v-model实现
function model(node, vm, exp) {
node.value = vm[exp]
new Watcher(vm, exp, value => {
node.value = value
})
node.addEventListener('input', e => {
vm[exp] = e.target.value
})
}
性能优化考虑
- 避免深度监听整个对象,可指定具体属性
- 对数组的特殊处理(重写数组方法)
- 异步更新队列(nextTick机制)
- 计算属性和缓存机制减少不必要的计算




