原生 JS 用 Object.defineProperty、Proxy、手动调用、Vue2 computed 选项、Vue3 computed 函数五种方式实现计算属性,分别通过依赖收集、缓存更新、事件绑定或框架响应式系统达成自动或可控的派生值计算。

一、使用原生 JavaScript 实现计算属性
在 HTML5 环境中,不依赖框架时可通过监听数据变化并手动触发更新逻辑来模拟计算属性行为。核心在于建立数据依赖关系,并在依赖项变更时重新执行计算函数。
1、定义一个响应式数据对象,使用 Object.defineProperty 为原始属性设置 getter 和 setter。
2、在 setter 中触发所有依赖该属性的计算函数重新求值。
3、将计算函数的返回值缓存,仅在依赖项变化时更新,避免重复计算。
立即学习 “ 前端免费学习笔记(深入)”;
4、通过闭包维护依赖收集机制,使每个计算函数能自动注册其访问过的响应式属性。
二、基于 Proxy 构造响应式系统实现计算属性
利用 ES6 Proxy 可拦截对象任意属性访问与赋值操作,比 Object.defineProperty 更全面地支持数组索引、新增属性等场景,适合构建现代计算属性机制。
1、创建一个reactive 函数,接收普通对象并返回其 Proxy 代理实例。
2、定义 computed 函数,接收一个计算函数作为参数,内部创建一个 Ref-like 响应式容器存储结果。
3、在 computed 内部首次执行计算函数时,通过全局依赖收集器记录当前活跃的计算函数与所读取的响应式属性之间的映射。
4、当 Proxy 拦截到某属性 set 操作时,通知所有依赖该属性的计算函数重新执行并更新缓存值。
三、手动调用计算函数并绑定事件更新
适用于轻量级页面或需精确控制更新时机的场景。通过显式绑定 DOM 事件或数据变更钩子,在特定动作发生后主动调用计算逻辑。
1、将计算逻辑封装为独立函数,例如 getFullName()、getTotalPrice()等。
2、在 input 事件监听器中调用该函数,并将返回值写入对应 DOM 元素的 textContent 或 value 属性。
3、对多个输入字段统一绑定 change 事件,事件处理函数内依次调用所有相关计算函数。
4、使用 setTimeout 或 requestAnimationFrame 包裹计算调用,确保 DOM 更新节奏可控,避免同步高频触发导致性能下降。
四、使用 Vue 2 的 computed 选项实现计算属性
Vue 2 通过 Object.defineProperty 劫持 data 中属性的 getter/setter,在内部追踪依赖关系,实现自动更新。computed 选项声明的函数会被包装为 Watcher 实例,具备缓存与懒执行特性。
1、在 Vue 组件的 computed 配置项中定义函数,函数体中访问 this 上的响应式数据。
2、Vue 自动分析函数执行过程中读取的响应式属性,并建立依赖关系。
3、当任一依赖属性发生变化时,对应 computed 函数被标记为“脏”,下次访问其返回值时才重新求值。
4、若计算属性被多次访问且依赖未变,则直接返回缓存结果,提升渲染效率。
五、使用 Vue 3 的 computed 函数实现计算属性
Vue 3 采用 Proxy 重写响应式系统,computed 函数作为独立 API 提供,既可用于组件内部,也可在 setup()或任意 JavaScript 模块中使用,返回一个 ref-like 只读响应式引用。
1、导入 {computed} from ‘vue‘,在 setup() 中调用 computed 传入计算函数。
2、计算函数中访问由 ref()或 reactive()创建的响应式状态,自动建立依赖追踪。
3、通过。value 访问计算结果,其行为与 ref 一致,支持在模板中直接使用或传递给其他响应式 API。
4、支持传入第二个参数配置对象,指定 get 和 set 方法,实现可写的计算属性,适用于双向绑定复杂逻辑场景。