修改 Javascript 对象副本会使原始对象在 Angular 5 Reactive Forms 中发生变化

Posted

技术标签:

【中文标题】修改 Javascript 对象副本会使原始对象在 Angular 5 Reactive Forms 中发生变化【英文标题】:Modifying an Javascript object copy makes the original object to change in Angular 5 Reactive Forms 【发布时间】:2018-10-21 19:54:04 【问题描述】:

我正在尝试创建我的反应式表单值对象的副本(使用扩展运算符或 Object.assign)并在将其发送到我的服务器之前对其应用一些更改。

这是构建我的表单的代码,它在我的模板中按预期工作:

newTask: FormGroup

this.newTask = this.formBuilder.group(
      partner:              [null, [Validators.required]],
      title:                [null, [Validators.required, Validators.minLength(5), Validators.maxLength(50)]],
      description:          [null, [Validators.minLength(10), Validators.maxLength(120)]],
      responsible:          [null, [Validators.required]],
      type:                 [null, [Validators.required]],
      priority:             [null, [Validators.required]],
      status:               [null, [Validators.required]],
      history:              this.formBuilder.array([])
    )

下面的代码说明了如何在我的历史数组中添加和删除元素:

createAction (action?) 
    return this.formBuilder.group(

      title: [action ? action.title : undefined, [Validators.required, Validators.minLength(5), Validators.maxLength(50)]],
      description: [action ? action.description : undefined, [Validators.required, Validators.minLength(10), Validators.maxLength(200)]],
      resolveAt: [action ? action.resolveAt : undefined],
      result: [action ? action.response : undefined, [Validators.minLength(10), Validators.maxLength(200)]],
      resolvedAt: [action ? action.resolvedAt : undefined],
      status: [action ? action.status : undefined, [Validators.required]],
      relatedPerson: [action ? action.relatedPerson : undefined]

    )
  

  addAction (action?): void 
    const history = this.newTask.get('history') as FormArray
    history.push(this.createAction(action || initialActionState))
  

  removeAction (i: number): void 
    const history = this.newTask.get('history') as FormArray
    history.removeAt(i)
  

在用户正确输入所有需要的数据后,当我提交表单时,这是我必须执行的修改:

let cleanVar = ...this.newTask.value
// I could also use let cleanVar = Object.assing(, this.newTask.value), the result is the same
    cleanVar.history.forEach(item => 
      item.status = item.status.string
      if (item.relatedPerson) item.relatedPerson = item.relatedPerson._id
    )
console.log(this.newTask.value)

如您所见,我正在尝试修改原始对象的副本,但是当我记录 this.newTask.value 时,更改也会传播到它。

我以前从未在对象副本方面遇到过这样的问题,所以我试图找出为什么会发生这种情况。也许它与我无法检测到的 Angular Reactive Forms 相关。

有人知道为什么会这样吗?

谢谢!

更新

这是我的 newTask.value 变量中的内容:

【问题讨论】:

没有副本。在这一行中,let cleanVar = ...this.newTask.value cleanVar 成为对对象文字的引用,但它又具有(引用)来自newTask.value 的“原始”元素。 感谢您的回答。那么我怎样才能创建我的对象的副本呢?我认为传播运算符和 Object.assign 创建没有引用的副本......而在其他情况下,我能够实现这一点,只有当我尝试复制反应形式的值时才会发生这种情况。 你能分享一下newTask.value里面的内容吗? 当然,在我的问题的更新版本中。 如果您可以访问项目中的 lodash 库,您只需使用 _.cloneDeep(objectToClone) 即可返回新副本。 lodash.com/docs#cloneDeep 【参考方案1】:

正如 marekful 和 Rikin 建议的那样,使用 lodash cloneDeep 是可行的方法:

import  cloneDeep  from 'lodash'

let clonedVar = cloneDeep (originalVar)

// do whatever you need with clonedVar and originalVar isn't touched

谢谢大家!

【讨论】:

以上是关于修改 Javascript 对象副本会使原始对象在 Angular 5 Reactive Forms 中发生变化的主要内容,如果未能解决你的问题,请参考以下文章

修改JavaScript对象的副本会导致原始对象发生更改

为什么在似乎是数据副本的操作上修改原始数据?

修改numpy中的索引对象

如何在修改其副本时避免更新原始数组? [复制]

Python:附加原始对象与附加对象副本[重复]

在Java中,如何返回对对象的引用,以便可以使用赋值运算符修改对象