You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

服务复杂对象类型属性变更检测的最佳实现方案

问题描述

我在寻找服务中复杂对象属性的变更检测最佳实现方式,当前场景中CarService既包含大量简单类型属性,也包含engine这类嵌套复杂对象,我不希望为每个属性单独编写getter/setter方法,需要检测到类似carService.engine.isGas = true这类嵌套属性的修改操作,示例代码如下:

export interface EngineType{
    isGas: false,
    isElectric: false,
    liters: 6
    cyclinders:6
}

export class CarService {
    engine: EngineType
}

export class HondaService {

    constructor(carService: CarService){}

    carService.engine.isGas = true;  // 需要检测到这个修改操作

}
实现方案

根据你的场景,优先推荐深度Proxy代理方案,侵入性最低,不需要修改现有属性赋值的写法,也不用给每个属性单独写访问器,同时支持顶层简单属性、任意深度嵌套属性的修改检测。

  • 核心逻辑:递归为目标对象的所有嵌套对象创建Proxy代理,拦截所有属性的set操作,只要有修改就触发变更通知。
  • 最小实现参考(适配示例里的TS/Angular风格场景):
import { Subject } from 'rxjs';

// 递归生成深度代理
function deepProxy<T extends object>(target: T, onChanged: () => void): T {
  const proxyHolder = new WeakMap();
  return new Proxy(target, {
    get(targetObj, prop, receiver) {
      const val = Reflect.get(targetObj, prop, receiver);
      // 取到的属性值是对象时,返回代理后的版本,保证后续嵌套修改能被拦截
      if (val && typeof val === 'object') {
        if (!proxyHolder.has(val)) {
          proxyHolder.set(val, deepProxy(val, onChanged));
        }
        return proxyHolder.get(val);
      }
      return val;
    },
    set(targetObj, prop, val, receiver) {
      const setResult = Reflect.set(targetObj, prop, val, receiver);
      // 任意属性赋值操作触发变更通知
      onChanged();
      return setResult;
    }
  }) as T;
}

// 改造CarService
export class CarService {
  engine: EngineType;
  // 变更通知流,需要监听变更的地方直接订阅这个流即可
  readonly changeNotify$ = new Subject<void>();

  constructor() {
    // 初始化所有状态,简单属性、嵌套对象都放在这里统一处理
    const initState = {
      engine: {
        isGas: false,
        isElectric: false,
        liters: 6,
        cyclinders: 6
      } as EngineType
      // 其他大量简单属性直接在这里追加即可,不需要额外写getter/setter
    };
    // 将代理后的状态挂载到服务实例上
    Object.assign(this, deepProxy(initState, () => {
      this.changeNotify$.next();
    }));
  }
}
  • 方案特点:
    • 不管是修改carService.engine.isGas这类深层嵌套属性,还是修改顶层的简单类型属性,甚至是整体替换engine属性为新对象,都能被稳定检测到
    • 新赋值的嵌套对象会被自动递归代理,不需要额外处理
    • 现有业务代码里直接给属性赋值的写法完全不需要改动,接入成本极低

其他可选方案

如果你的场景允许约束属性修改的写法,也可以选择以下方案:

  • 不可变数据模式:要求所有属性修改都通过生成新对象的方式完成,禁止直接修改原对象属性,服务内部用可观察对象存储状态,每次更新推送新的状态值,搭配引用对比即可检测变更。这种方案逻辑更清晰,但需要团队严格遵守不可变修改约定,直接改嵌套属性的写法会绕过检测。
  • 状态管理类库:如果是Angular技术栈,可以直接用Signals、Component Store这类工具做状态托管,自带变更检测能力,但需要按照类库的要求编写状态更新逻辑,相比Proxy方案有一定接入成本。

内容的提问来源于stack exchange,提问作者Jambione

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 09:42:25