vue自己实现双向绑定
实现 Vue 双向绑定的核心原理
双向绑定的核心是通过数据劫持结合发布-订阅模式实现的。主要涉及 Object.defineProperty 或 Proxy 来监听数据变化,并通过观察者模式通知视图更新。
使用 Object.defineProperty 实现
通过 Object.defineProperty 劫持对象的属性,在属性被访问或修改时触发 getter 和 setter。
function defineReactive(obj, key, val) {
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.addSub(Dep.target);
}
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify();
}
});
}
实现依赖收集(Dep 类)
Dep 类用于管理依赖(Watcher 实例),并在数据变化时通知所有订阅者。

class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
Dep.target = null;
实现观察者(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;
const value = this.vm._data[this.exp];
Dep.target = null;
return value;
}
update() {
const newValue = this.vm._data[this.exp];
if (newValue !== this.value) {
this.value = newValue;
this.cb(newValue);
}
}
}
实现数据监听
遍历对象的所有属性,递归监听嵌套对象。

function observe(obj) {
if (!obj || typeof obj !== 'object') return;
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key]);
observe(obj[key]);
});
}
实现 Vue 类
将数据、观察者和模板绑定整合。
class Vue {
constructor(options) {
this._data = options.data;
observe(this._data);
this._compile(options.el);
}
_compile(el) {
const element = document.querySelector(el);
const nodes = element.children;
Array.from(nodes).forEach(node => {
if (node.hasAttribute('v-model')) {
const exp = node.getAttribute('v-model');
node.addEventListener('input', e => {
this._data[exp] = e.target.value;
});
new Watcher(this, exp, val => {
node.value = val;
});
}
});
}
}
使用 Proxy 实现(现代方式)
Proxy 可以更简洁地实现数据劫持,支持监听数组变化。
function reactive(obj) {
const dep = new Dep();
return new Proxy(obj, {
get(target, key) {
if (Dep.target) {
dep.addSub(Dep.target);
}
return Reflect.get(target, key);
},
set(target, key, value) {
const result = Reflect.set(target, key, value);
dep.notify();
return result;
}
});
}
完整示例代码
将上述部分整合为一个完整的双向绑定实现:
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
Dep.target = null;
class Watcher {
constructor(vm, exp, cb) {
this.vm = vm;
this.exp = exp;
this.cb = cb;
this.value = this.get();
}
get() {
Dep.target = this;
const value = this.vm._data[this.exp];
Dep.target = null;
return value;
}
update() {
const newValue = this.vm._data[this.exp];
if (newValue !== this.value) {
this.value = newValue;
this.cb(newValue);
}
}
}
function defineReactive(obj, key, val) {
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.addSub(Dep.target);
}
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify();
}
});
}
function observe(obj) {
if (!obj || typeof obj !== 'object') return;
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key]);
observe(obj[key]);
});
}
class Vue {
constructor(options) {
this._data = options.data;
observe(this._data);
this._compile(options.el);
}
_compile(el) {
const element = document.querySelector(el);
const nodes = element.children;
Array.from(nodes).forEach(node => {
if (node.hasAttribute('v-model')) {
const exp = node.getAttribute('v-model');
node.addEventListener('input', e => {
this._data[exp] = e.target.value;
});
new Watcher(this, exp, val => {
node.value = val;
});
}
});
}
}
// 使用示例
const vm = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
关键点总结
- 数据劫持:通过
Object.defineProperty或Proxy监听数据变化。 - 依赖收集:在 getter 中收集依赖(Watcher),在 setter 中触发更新。
- 发布-订阅模式:
Dep管理依赖,Watcher订阅变化并执行回调。 - 模板编译:解析模板中的指令(如
v-model),绑定事件和更新函数。
以上实现是一个简化版本,Vue 的实际实现更复杂,包括虚拟 DOM、组件系统等。






