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

JavaScript纯函数实现不修改原状态时如何保留正确引用关系?

纯函数实现下保留引用关联的解决方案

问题根因

非纯函数版本直接修改原始对象,result数组和原始ps数组的元素指向同一个引用,result[0].y[0]存储的ps[1]后续被修改时,访问的是同一个内存地址的对象,因此两次打印相等。
纯函数版本中incrX返回的是浅拷贝生成的新对象,result[1]是新生成的实例,而存入result[0].y的是未修改的原始ps[1]引用,两者指向不同的内存地址,因此打印结果不一致。

你提到的“引用的引用”思路在JavaScript中是可行的,JS没有原生二级指针语法,但可以通过间接容器实现同类效果,也可以通过调整操作顺序实现需求:

方案1:使用ref间接容器实现“引用的引用”

通过一层固定引用的容器包裹实际对象,所有关联存储都指向容器,更新时只替换容器内部的实际对象,容器本身的引用永远保持不变,就能保证关联引用的正确性。
示例代码:

class P {
  constructor() {
    this.x = 0
    this.y = []
  }
}

// 纯函数逻辑保持不变
const incrX = (p) => ({ ...p, x: p.x + 1 })
const incrY = (p, q) => ({ ...p, y: [...p.y, q] })

// 所有实例包裹在ref容器中,容器引用固定
const ps = [
  { value: new P() },
  { value: new P() }
]

const result = ps.map((_, i) => {
  if (i === 0) {
    // 存储的是ref容器的固定引用
    return { ...ps[i], value: incrY(ps[i].value, ps[1]) }
  } else {
    return { ...ps[i], value: incrX(ps[i].value) }
  }
})

// 访问时取容器内部的实际对象
console.log(result[0].value.y[0].value === result[1].value) // 输出 true

方案2:调整操作顺序,先更新再关联

如果不想引入额外的容器层,也可以先完成所有对象的更新操作,再处理对象之间的关联逻辑,保证存入的是更新后的新对象引用。
示例代码:

class P {
  constructor() {
    this.x = 0
    this.y = []
  }
}

const incrX = (p) => ({ ...p, x: p.x + 1 })
const incrY = (p, q) => ({ ...p, y: [...p.y, q] })

const ps = [new P(), new P()]

// 第一步先完成所有实例的更新操作
const tempResult = ps.map(p => incrX(p))
// 第二步再处理关联逻辑,传入更新后的实例引用
const result = tempResult.map((p, i) => i === 0 ? incrY(p, tempResult[1]) : p)

console.log(result[0].y[0] === result[1]) // 输出 true

方案选型

  • ref容器方案适合对象依赖关系复杂、互相引用多的场景,不需要调整操作顺序,缺点是多了一层属性访问。
  • 调整顺序方案适合依赖关系清晰的简单场景,代码更直观无额外开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 00:54:06