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

JavaScript中如何防止通过get方法修改构造函数内的状态对象

问题原因

getState直接返回了内部私有对象SecretState的引用,JavaScript里对象属于引用类型,外部拿到这个引用后可以直接修改对象属性,完全绕过setState的逻辑,所以执行m.getState().name = 'Alice'时会直接改动内部存储的真实状态,最终输出不符合预期。

可行实现方案
  • 方案1:返回状态副本(通用首选)
    不直接返回原对象引用,而是返回状态的拷贝,外部修改拷贝对象不会影响内部真实状态。
    单层简单状态用浅拷贝即可,性能开销极低:
    function State(){
      const SecretState = {
        name: 'bob'
      }
      // 浅拷贝后返回
      this.getState = () => ({ ...SecretState });
      this.setState = (name) => SecretState.name = name;
    }
    const m = new State()
    m.setState('Smith')
    m.getState().name = 'Alice' // 修改的是临时生成的拷贝对象,不影响内部状态
    console.log(m.getState().name) // 输出 Smith
    
    如果状态存在多层嵌套结构,用原生structuredClone做深拷贝即可,避免嵌套属性被篡改:
    this.getState = () => structuredClone(SecretState);
    
  • 方案2:直接返回属性原始值
    如果不需要一次性获取整个状态对象,直接返回目标属性的原始值即可。原始类型是值传递,外部拿到值后的修改操作和内部状态完全无关:
    function State(){
      const SecretState = {
        name: 'bob'
      }
      this.getName = () => SecretState.name;
      this.setName = (name) => SecretState.name = name;
    }
    const m = new State()
    m.setName('Smith')
    const currentName = m.getName()
    // 这里修改的是独立的字符串原始值,不会改动内部状态
    currentName + '123'
    console.log(m.getName()) // 输出 Smith
    
  • 方案3:返回只读代理(适合大体积状态场景)
    如果状态对象体积很大,每次全量拷贝的性能开销过高,可以返回原对象的只读Proxy代理,拦截所有外部修改操作,既不会改动原对象,也没有拷贝开销:
    function State(){
      const SecretState = {
        name: 'bob'
      }
      const readonlyHandler = {
        set() {
          console.warn('禁止直接修改状态,请使用setState方法更新')
          return false
        },
        get(target, prop) {
          const val = target[prop]
          // 嵌套对象也递归生成只读代理
          return typeof val === 'object' && val !== null ? new Proxy(val, readonlyHandler) : val
        }
      }
      const readOnlyState = new Proxy(SecretState, readonlyHandler)
      this.getState = () => readOnlyState;
      this.setState = (name) => SecretState.name = name;
    }
    const m = new State()
    m.setState('Smith')
    m.getState().name = 'Alice' // 触发警告,修改不生效
    console.log(m.getState().name) // 输出 Smith
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 20:48:21