es6 class 本身不提供响应式能力,需结合 proxy 或 object.defineproperty 实现;推荐用 proxy 封装,在构造函数中返回代理对象,通过 get 收集依赖、set 触发更新,并对嵌套对象递归代理。

ES6 Class 本身不提供响应式能力,但可以结合 Proxy 或 Object.defineProperty 封装成可监听数据变化的类。核心思路是:用 Class 管理状态结构,用代理机制拦截读写操作,触发视图更新。
用 Proxy 封装响应式 Class(推荐)
Proxy 更强大、更灵活,能监听新增/删除属性、数组索引访问等,适合现代响应式实现。
- 在 Class 构造函数中,用
new Proxy(this, handler)包裹实例,把原始对象设为代理目标 - 定义
get拦截器:收集依赖(如当前正在执行的渲染函数),可用 WeakMap 存储 key → effect 映射 - 定义
set拦截器:赋值后遍历触发对应 key 的所有 effect 函数(即更新 DOM 或重新计算) - 为避免重复代理嵌套对象,
get中对返回值是对象的属性自动递归代理(懒代理)
封装一个简易 Reactive 类示例
以下是一个最小可行实现,不依赖框架,仅用原生 JS:
class Reactive {
constructor(data) {
this._data = data;
return new Proxy(this._data, {
get: (target, key) => {
// 这里可接入依赖收集(例如:activeEffect && track(target, key))
const value = target[key];
return typeof value === 'object' && value !== null
? new Proxy(value, this)
: value;
},
set: (target, key, value) => {
target[key] = value;
// 这里可触发更新(例如:trigger(target, key))
console.log(`响应式更新: ${key} =`, value);
return true;
}
});
}
}
使用时:const state = new Reactive({ count: 0, name: 'Vue' });,后续修改 state.count++ 即可被拦截。
配合模板更新实现双向绑定
Class 提供数据,还需连接视图。常见做法:
- 在
set拦截器中调用render()或触发自定义事件(如dispatchEvent(new CustomEvent('change'))) - 为 input 元素添加
input监听,将用户输入同步回响应式对象(state.xxx = e.target.value) - 用
document.querySelector找到对应节点,用 innerHTML / textContent 更新文本内容
注意事项与限制
直接用 Class 实现完整响应式需额外补全很多细节:
- Proxy 无法监听对象属性的添加/删除(除非用
Reflect.set+ 手动 trigger),但 Vue 3 已解决 - 数组方法如
push、pop默认不触发 set,需重写或用splice等可拦截方法 - Class 原型上的方法不会被 Proxy 拦截,只代理实例属性;方法内访问
this.xxx才会走 get/set - 避免对同一对象重复代理,可用
WeakMap缓存已代理对象
不复杂但容易忽略:真正实用的响应式系统,Class 只是组织状态的外壳,Proxy(或 defineProperty)才是响应式的引擎,而依赖追踪和更新调度才是让“响应”落地的关键环节。











