vue双向绑定实现函数
Vue 双向绑定实现原理
Vue 的双向绑定是通过数据劫持结合发布者-订阅者模式实现的,核心是 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)。
基于 Object.defineProperty 的实现(Vue 2.x)
-
数据劫持 通过
Object.defineProperty劫持对象的属性,在属性被访问或修改时触发 getter 和 setter。function defineReactive(obj, key, val) { Object.defineProperty(obj, key, { get() { console.log(`获取 ${key}: ${val}`); return val; }, set(newVal) { if (newVal !== val) { console.log(`设置 ${key}: ${newVal}`); val = newVal; } } }); } -
依赖收集 在 getter 中收集依赖(订阅者),在 setter 中通知依赖更新。
class Dep { constructor() { this.subscribers = []; } depend() { if (target && !this.subscribers.includes(target)) { this.subscribers.push(target); } } notify() { this.subscribers.forEach(sub => sub()); } } let target = null; function defineReactive(obj, key, val) { const dep = new Dep(); Object.defineProperty(obj, key, { get() { dep.depend(); return val; }, set(newVal) { if (newVal !== val) { val = newVal; dep.notify(); } } }); } -
观察者 创建一个观察者函数,用于更新视图。
function watcher(fn) { target = fn; fn(); target = null; } -
完整示例

const data = { text: 'hello' }; defineReactive(data, 'text', data.text); watcher(() => { console.log('视图更新:', data.text); }); data.text = 'world'; // 触发视图更新
基于 Proxy 的实现(Vue 3.x)
Vue 3.x 使用 Proxy 替代 Object.defineProperty,解决了无法监听数组变化和对象新增属性的问题。
-
Proxy 数据劫持
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) { if (!activeEffect) return; 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 dep = depsMap.get(key); if (dep) { dep.forEach(effect => effect()); } } let activeEffect = null; function effect(fn) { activeEffect = fn; fn(); activeEffect = null; } -
完整示例
const data = reactive({ text: 'hello' }); effect(() => { console.log('视图更新:', data.text); }); data.text = 'world'; // 触发视图更新
双向绑定的实现
双向绑定通常用于表单输入,结合 v-model 指令实现。
-
模板编译 将模板中的
v-model解析为事件监听和属性绑定。<input v-model="message" /> <!-- 等价于 --> <input :value="message" @input="message = $event.target.value" /> -
手动实现双向绑定
function bindInput(data, key, input) { input.value = data[key]; input.addEventListener('input', (e) => { data[key] = e.target.value; }); } const data = reactive({ message: '' }); const input = document.querySelector('input'); bindInput(data, 'message', input); effect(() => { console.log('数据更新:', data.message); });
总结
- Vue 2.x 使用
Object.defineProperty实现数据劫持,需要递归遍历对象属性。 - Vue 3.x 使用
Proxy实现数据劫持,能监听数组和对象新增属性。 - 双向绑定是数据劫持与事件监听的结合,通过
v-model简化操作。






