首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >除了 Proxy,前端还有哪些实现数据响应式的路子?

除了 Proxy,前端还有哪些实现数据响应式的路子?

原创
作者头像
小焱
发布2025-08-28 20:33:50
发布2025-08-28 20:33:50
9400
代码可运行
举报
文章被收录于专栏:前端开发前端开发
运行总次数:0
代码可运行

除了 Proxy,前端还有哪些实现数据响应式的路子?

其实搞懂响应式不用死记概念,本质就是怎么让“数据变了的时候,页面/逻辑自动跟着变”——除了现在主流的 Proxy,以前不少框架和手写方案也有自己的玩法,说几个实际开发里见过或用过的:

先明确个前提:不管哪种方法,核心都是解决“怎么知道数据变了”和“变了之后要通知谁”这两个问题,只是思路不一样。

1. Object.defineProperty:Vue 2 时代的“老伙计”,逐个属性盯梢

这应该是很多人最早接触的响应式实现了,Vue 2 就是靠它撑起来的。原理特别实在:给对象的每个属性单独装“监听器”。

举个例子,你有个 data = { name: 'Vue', version: 2 },要让 name 变的时候页面更新,就得这么搞:

Object.definePropertyname 重新包装一遍,加两个钩子:

  • getter:每次有人读 data.name(比如页面渲染要用到),就偷偷记下来“谁在用这个值”(这步叫“依赖收集”);
  • setter:每次有人改 data.name(比如用户点了按钮),就去通知之前记下来的“使用者”:“快更新!数据变了!”

但这办法有两个绕不开的坑:

一是只能盯已有的属性。如果后来想加个新属性,比如 data.author = 'Evan',直接加是没反应的——因为没给这个新属性装 getter/setter,所以 Vue 2 才要搞个 $set 专门干这事;

二是对数组不友好。比如你想改数组的某一项 arr[0] = 1,或者直接改长度 arr.length = 0,这两种操作它监听不到,所以 Vue 2 只能偷偷重写数组的 pushsplice 这些常用方法,才能勉强覆盖数组操作。

现在除了要兼容 IE 的老项目,基本没人主动用这个了,但理解它能帮你搞懂响应式的核心逻辑。

2. 脏检查:AngularJS 玩过的“笨办法”,定期查岗

这个思路特别直白,甚至有点“粗暴”——不主动盯数据,而是等可能改数据的操作(比如用户点按钮、发完请求)结束后,集中搞一次“大检查”。

比如页面里用了 data.count,流程大概是这样:

  • 先把 data.count 当前的值存下来(比如是 0);
  • 等用户操作完,再拿现在的值跟之前存的比;
  • 如果不一样(比如变成 1 了),就说明数据“脏了”,赶紧更新页面;
  • 有时候还得反复查好几轮,比如 A 数据变了导致 B 数据变,B 又导致 C 变,得查到所有数据都稳定了才停。

这种方式的好处是实现简单——不用折腾属性拦截,不用管对象还是数组,反正最后统一对比就行。但缺点也很明显:性能拉胯。如果页面里要监控的数据多,每次检查都要遍历所有数据,数据量大的时候页面会明显卡一下,所以后来 Angular 也放弃了这个思路,换成了类似 Vue 的响应式方案。

3. 发布-订阅模式:自己写响应式的“万能骨架”

这个不算具体技术,更像一种设计思路,但几乎所有响应式框架底层都用到了——本质就是“消息通知”:数据是“发布者”,用数据的地方(比如页面、逻辑函数)是“订阅者”,中间搞个“消息中心”牵线。

举个手写的例子,比如你想让 data.count 变的时候,页面上的数字和控制台日志都更新:

  • 先搞个“消息中心”(比如叫 Dep),里面有个列表存所有“要听消息的人”;
  • 当页面第一次渲染 data.count 时,就让页面的更新函数去“订阅”这个数据——也就是告诉消息中心:“我要听 data.count 的动静”;
  • 当你改 data.count 时,就让 data.count 这个“发布者”通知消息中心:“我变了!”;
  • 消息中心再挨个喊订阅者:“快干活!数据更新了!”,于是页面和日志就一起更新了。

这种方式的灵活性特别高,不管你用 Proxy 还是 Object.defineProperty,都能套这个骨架。比如自己写个简单的状态管理,或者给某个组件单独加响应式逻辑,用这个思路写起来又清晰又好控制。

4. Object.observe:被标准“干掉”的原生方案,踩过坑的都懂

这个算个“历史遗留问题”了——早年 ES6 提案里有个原生 API 叫 Object.observe,本来是想让浏览器直接支持监听对象变化,不用开发者自己写拦截逻辑。

用法特别简单,比如:

代码语言:javascript
代码运行次数:0
运行
复制
const obj = { name: 'test' };
Object.observe(obj, changes => {
  changes.forEach(change => {
    console.log(`属性 ${change.name} 从 ${change.oldValue} 改成了 ${change.object[change.name]}`);
  });
});
obj.name = 'new test'; // 会自动触发上面的回调

但这玩意儿后来被 ES 标准砍掉了——主要是因为太“死板”,没法灵活控制监听的范围(比如只想监听某个属性,不想监听整个对象),而且当时浏览器兼容性也差,最后没人用了。现在提这个,主要是避免有人在旧文档里看到这个 API 去踩坑。

最后总结下实际用法

现在前端圈里,真正常用的就两类:

  1. 现代项目首选 Proxy:Vue 3、React 的一些状态库(比如 MobX)都用它,能直接盯整个对象,新增/删除属性、数组操作都能搞定,性能也比 Object.defineProperty 好;
  2. 自己写简单逻辑用“发布-订阅+拦截”:比如给某个组件写局部响应式,不用引入框架,就用发布-订阅搭骨架,再配合 Proxy(或 Object.defineProperty)做数据拦截,灵活又轻量;
  3. 至于脏检查和 Object.observe,了解下原理就行,实际开发里基本碰不到了——除非你要维护十年前的 AngularJS 项目。

其实响应式没那么玄乎,核心就是“盯数据”和“发通知”,不管用哪种方法,把这两个逻辑理清楚,就算搞懂了。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 除了 Proxy,前端还有哪些实现数据响应式的路子?
    • 1. Object.defineProperty:Vue 2 时代的“老伙计”,逐个属性盯梢
    • 2. 脏检查:AngularJS 玩过的“笨办法”,定期查岗
    • 3. 发布-订阅模式:自己写响应式的“万能骨架”
    • 4. Object.observe:被标准“干掉”的原生方案,踩过坑的都懂
    • 最后总结下实际用法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档