proxy实现vue
使用Proxy实现Vue响应式系统
Proxy是ES6引入的特性,能够拦截对象的操作,Vue3利用Proxy替代了Vue2中的Object.defineProperty来实现响应式。以下是实现核心逻辑的方法:
创建响应式对象
function reactive(target) {
return new Proxy(target, {
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;
}
});
}
依赖收集与触发

const targetMap = new WeakMap();
let activeEffect = null;
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 effects = depsMap.get(key);
effects && effects.forEach(effect => effect());
}
副作用函数处理
function effect(fn) {
activeEffect = fn;
fn();
activeEffect = null;
}
实现计算属性
基于上述响应式系统,可以扩展实现计算属性:

function computed(getter) {
let value;
let dirty = true;
const runner = effect(getter, {
lazy: true,
scheduler() {
dirty = true;
trigger(obj, 'value');
}
});
const obj = {
get value() {
if (dirty) {
value = runner();
dirty = false;
}
track(obj, 'value');
return value;
}
};
return obj;
}
实现模板编译
结合Proxy响应式系统,可以模拟Vue的模板编译:
function compile(template) {
return function render(ctx) {
const div = document.createElement('div');
div.innerHTML = template.replace(/{{(.*?)}}/g, (_, exp) => {
return exp.split('.').reduce((obj, k) => obj[k], ctx);
});
return div.firstChild;
};
}
完整示例组合
将各部分组合成简易Vue实现:
class MiniVue {
constructor(options) {
this.$options = options;
this.$data = reactive(options.data());
this.proxyData();
this.$el = document.querySelector(options.el);
this.compile();
}
proxyData() {
for (const key in this.$data) {
Object.defineProperty(this, key, {
get: () => this.$data[key],
set: val => (this.$data[key] = val)
});
}
}
compile() {
const render = compile(this.$options.template);
effect(() => {
const newNode = render(this.$data);
this.$el.innerHTML = '';
this.$el.appendChild(newNode);
});
}
}
注意事项
Proxy相比Object.defineProperty的优势在于能检测到新增属性、数组索引变化等,但需要注意以下问题:
- 浏览器兼容性:Proxy无法被polyfill
- 性能考虑:嵌套对象的处理需要递归代理
- 原始值处理:需要额外包装为对象才能被代理
这种实现展示了Vue响应式原理的核心思想,实际Vue3的实现还包含更多优化和边界情况处理。






