面试:vue2和vue3的双向绑定原理有什么不同
1、不同
1.1 响应式实现原理
Vue2 - Object.defineProperty
// Vue2 的响应式原理简化实现
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;
// 触发更新
updateView();
}
}
});
}
const data = { name: 'Vue2' };
defineReactive(data, 'name', data.name);
data.name = 'New Value'; // 触发 setter
局限性:
- 无法检测对象属性的添加/删除
- 无法检测数组索引和长度的变化
- 需要额外的 API(Vue.set, Vue.delete)
// Vue2 的问题示例
const vm = new Vue({
data: {
user: { name: 'John' },
list: [1, 2, 3]
}
});
// ❌ 无法响应式
vm.user.age = 25; // 新增属性
delete vm.user.name; // 删除属性
vm.list[0] = 999; // 数组索引设置
vm.list.length = 0; // 数组长度修改
// ✅ 必须使用特殊 API
Vue.set(vm.user, 'age', 25);
Vue.set(vm.list, 0, 999);
Vue3 - Proxy:
// Vue3 的响应式原理简化实现
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
console.log(`读取 ${String(key)}`);
const result = Reflect.get(target, key, receiver);
return typeof result === 'object' ? reactive(result) : result;
},
set(target, key, value, receiver) {
console.log(`设置 ${String(key)}: ${value}`);
const result = Reflect.set(target, key, value, receiver);
// 触发更新
updateView();
return result;
},
deleteProperty(target, key) {
console.log(`删除 ${String(key)}`);
const result = Reflect.deleteProperty(target, key);
updateView();
return result;
}
});
}
const data = reactive({ name: 'Vue3', list: [1, 2, 3] });
data.name = 'New Value'; // 触发 set
data.age = 25; // 触发 set - 新增属性
delete data.name; // 触发 deleteProperty
data.list[0] = 999; // 触发 set - 数组索引
data.list.push(4); // 触发 set - 数组方法
优势:
- ✅ 支持对象属性的添加/删除
- ✅ 支持数组索引和长度的变化
- ✅ 深度监听,性能更好
- ✅ 不需要特殊 API
1.2 性能对比

1.3 源码结构差异
Vue2 响应式结构
// Vue2 源码简化
class Observer {
constructor(value) {
this.value = value;
this.walk(value);
}
walk(obj) {
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key]);
});
}
}
function defineReactive(obj, key, val) {
const dep = new Dep(); // 每个属性一个依赖收集器
// 递归处理嵌套对象
if (typeof val === 'object') {
new Observer(val);
}
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.depend(); // 收集依赖
}
return val;
},
set(newVal) {
if (newVal !== val) {
val = newVal;
// 新值是对象也要响应式
if (typeof newVal === 'object') {
new Observer(newVal);
}
dep.notify(); // 通知更新
}
}
});
}
Vue3 响应式结构
// Vue3 源码简化
const reactiveMap = new WeakMap();
function reactive(target) {
return createReactiveObject(target, reactiveMap);
}
function createReactiveObject(target, proxyMap) {
// 缓存检查
const existingProxy = proxyMap.get(target);
if (existingProxy) return existingProxy;
const proxy = new Proxy(target, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver);
// 依赖收集
track(target, key);
// 惰性递归代理
if (typeof res === 'object' && res !== null) {
return reactive(res);
}
return res;
},
set(target, key, value, receiver) {
const oldValue = target[key];
const result = Reflect.set(target, key, value, receiver);
if (result && oldValue !== value) {
// 触发更新
trigger(target, key);
}
return result;
}
});
proxyMap.set(target, proxy);
return proxy;
}
2、面试回答技巧
可以这样组织回答:“Vue2 和 Vue3 在双向绑定原理上的主要区别在于响应式系统的实现”
- 核心技术不同:
- Vue2 使用 Object.defineProperty 实现数据劫持
- Vue3 使用 Proxy 实现代理拦截
- 能力差异:
- Vue2 无法检测对象属性的添加/删除和数组索引变化,需要 Vue.set/Vue.delete
- Vue3 可以全面检测各种数据变化,包括新增属性、数组操作等
- 性能优化:
- Vue2 初始化时递归遍历所有属性,性能开销较大
- Vue3 使用惰性代理,按需响应,内存占用更优


2279

被折叠的 条评论
为什么被折叠?



