【问题标题】:Array.push performs deep copy instead of shallow copyArray.push 执行深拷贝而不是浅拷贝
【发布时间】:2016-09-27 02:19:54
【问题描述】:

上下文

我正在为我的 web 应用程序使用 Typescript/Angular2 RC1,并且我有两个类。在 class1(Angular2 服务)中,我有一个变量 myVar = [obj1, obj2, obj3],在 class2(Angular2 组件)中,我在使用 viewInjector 注入服务的构造函数中得到 myLocalVar = class1.myVar。

问题

在 class2 中,我使用 push 复制 myVar(浅复制,因为它复制对象)所以 myLocalVar 等于 [obj1, obj2, obj3](这样 objX={number:X})。当我更改一项例如:myVar[0]={number:5} in class1 时,更改不会出现在我的 class2 中 myLocalVar 和 myLocalVar[0].number 将等于 1。但是,class2 的myVar 发生了变化……看来this.myLocalVar.push(this.myVar[int]); 创建了深拷贝而不是浅拷贝。

Typescript 是否会改变 Javascript 中 push 的行为?如果是,我应该怎么做才能保留引用并做浅拷贝?

代码示例

@Injectable()

export class Class1{

    public myVar:any[];

    constructor(){
        this.myVar = [{number: 1}, {number: 2}, {number: 3}];
    }

    changeVar(newVar):void{
        this.myVar[0] = newVar; // newVar = {number: 5}
    }
}

@Component({
    selector: 'class2',
    viewInjector: [Class1],
    templateUrl: 'someURL'
})
export class Class2{

    private myLocalVar:any[] = [];

    constructor(class1: Class1){
        this.myVar = class1.myVar;
    }

    showVars():void{
        console.log(this.myLocalVar[0]);
        console.log(this.myVar[0]);
    }

    ngOnInit(){
        for(let int = 0; int < this.myVar.length; int++){
            this.myLocalVar.push(this.myVar[int]);
        }
    }
}

console.log 将打印两个不同的值:console.log(this.myLocalVar[0]) 打印1 和console.log(this.myVar[0]); 在changeVar() 被第三方调用后打印5!

编辑

这是一个证明问题的plunker:

  • 单击显示,检查您的控制台,您将看到相同的值
  • 点击更改
  • 再次单击显示,您将看到myVar 和myLocalVar 的两个不同值

我需要的是每次更改myVar[x]=newObj 我希望myLocalVar 反映该更改。如果您希望您的答案得到验证,请提供该问题的解决方案。

【问题讨论】:

  • 我认为您的错误是认为push 创建了副本。您可以轻松地将相同的对象引用推送到多个数组。如果您需要副本,请尝试使用angular.copy()
  • @charlietfl 我知道push 做了浅拷贝,但似乎在这种情况下它做了深拷贝!否则,为什么我会得到两个不同的值?
  • 创建一个复制问题的简单演示。我怀疑 angular2 重载 Array.push 是否会让开发人员感到麻木,从而违反良好做法
  • "我知道 push 做了一个浅拷贝" --- 它不做任何拷贝。
  • 您正在覆盖整个对象而不更改其属性this.myVar[0] = {number:newVar}; 与this.myVar[0].number=newVar 不同。这就是为什么你认为它是一个副本,但你完全破坏了原始参考

标签: javascript typescript angular


【解决方案1】:

您有这个问题是因为myLocalVar 和myVar 是两个不同的引用。意思是,它们是两个不同的数组容器。

当你将元素从myVar 推送到myLocalVar 时,你会将myVar 中元素的引用推送到myLocalVar。所以 如果

myVar = [{name: 1}, {name: 2}] 你有两个对象,两个对象的引用都被推入myLocalVar。

当您调用changeVar 方法时,您基本上将myVar 中的元素引用替换为新的对象引用。但是,对被替换元素的旧引用仍然存在并由myLocalVar 引用,因此您会看到结果。

那么解决方案呢?

您需要更改 changeVar 方法设置值的方式。而不是做this.myVar[0] = {number:newVar};,你应该做this.myVar[0]['number'] = newVar; 这样维护引用。

【讨论】:

    【解决方案2】:

    “Object.assign”做浅拷贝。

    (<any>Object).assign(this.shallowCopyObject, this.myObject);
    

    【讨论】:

      【解决方案3】:

      您的意图似乎是更新对象的值,但实际上您正在创建一个新对象并将该新对象插入到原始数组中(仅)。

      这会如你所愿:

      changeVar(newVar: Object): void {
          this.myVar[0].number = newVar.number;
      }
      

      您链接到的 plunker 代码与发布的代码不同步。在 plunker 的情况下,您传递的是一个数字,而不是一个对象。它有:

      changeVar(newVar): void {
          this.myVar[0] = {number:newVar}; // newVar = {number: 5}
      }
      

      在这种情况下,改为:

      changeVar(newVar: number): void {
          this.myVar[0].number = newVar;
      }
      

      【讨论】:

        【解决方案4】:

        改变

        ngOnInit(){
            for(let int = 0; int < this.myVar.length; int++){
                this.myLocalVar.push(this.myVar[int]);
            }
        }
        

        到

        ngOnInit(){
          this.myLocalVar = this.myVar;
        }
        

        在第一个唯一引用的数组元素被复制。在数组的第二个引用被复制?

        【讨论】:

        • 我做不到……我的真实情况是我过滤了一些对象
        猜你喜欢
        • 2018-02-26
        • 2010-11-19
        • 1970-01-01
        • 2012-04-12
        • 1970-01-01
        • 2015-01-13
        • 2011-09-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多