Angular4 copy object without reference?

Viewed 21804

Inside a component I tried to copy an object from a service that could be modified inside the component, but should stay in the service.

private test;

public ngOnInit(): {
  console.log(this.someService.test.someProperty) //'old'
  this.test = this.someService.test;

  //not working as well?!
  //this.test = Object.assign({}, this.someService.test);
  //this.test = Object.create(this.somerService.test);

  this.changeTest();
}

public changeTest(): void {
  this.test.someProperty = 'new';
}

after the init both, this.test.someProperty as well as this.someService.test.someProperty are changed to new even though the last should stay old?

Why is that happening, and how to only change properties of this.test

3 Answers

It's because Object.assign is a shallow merge, it's only merging the top level, so the top level is referencing the same object in both the service and the component.

I personally use lodash's merge when I need to deep merge objects:

this.test = _.merge({}, this.someService.test)

Also see: How to deep merge instead of shallow merge?

You can also deep clone the object with:

this.test = JSON.parse(JSON.stringify(this.someService.test));

Also see: How to Deep clone in javascript

Actually Object assign works as in your example. Created plunker to prove it

  this.test = Object.assign({}, this.someService.test);

I personally prefer to add a clone function in the class. It iterates through the object fields and assign the matching values.

export class Car {

    constructor(
        public id: number, 
        public name: String) { }

    clone(other : Car) : void {
        let k: keyof Car;
        for (k in other) {
            const v = other[k];
            (this[k] as (typeof v)) = v;
          }
    }
}

Usage :

var car1 = new Car(1, "Amg");
var car2 = new Car(2, "205");
car1.clone(car2);
Related