0

I must be doing something wrong.

  1. Instantiate Person class as Bob with name 'Bob'
  2. Clone Bob as new var Alice
  3. Rename Alice with name 'Alice'
  4. Log names of Bob & Alice

I expect Bob's name will remain 'Bob', but it has updated to 'Alice', despite not updating Bob...?

class Person {
  constructor(attr) {
    this.attr = attr;
  }

  talk() {
    console.log('My name is ' + this.attr.name);
  }
}

function clone(obj) {
  return Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}

var Bob = new Person({
  name: 'Bob'
});

var Alice = clone(Bob);
Alice.attr.name = 'Alice';

Alice.talk();
Bob.talk();

Thanks in advance.

Ori Drori
  • 183,571
  • 29
  • 224
  • 209
blindmikey
  • 137
  • 1
  • 10

2 Answers2

2

Object.assign performs a shallow copy, so Bob and Alice will have their own copy of the attr reference, but they refer to the same nested object. attr.name is still a shared string.

You need to perform a deep(er) copy, or else reassign the attr property:

Alice.attr = { name: 'Alice' };
trincot
  • 317,000
  • 35
  • 244
  • 286
  • This insight is perfect. Thank you! – blindmikey Nov 21 '17 at 22:04
  • Cloning is ambiguous when it comes to user defined objects, which may have parent-like references, or cyclic references, or functions, and getters which have side-effects, ...etc. See for instance [this answer I gave to a deep clone question](https://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript/40294058#40294058). – trincot Nov 21 '17 at 22:09
1

The simplest solution for cloning is:

var cloned = JSON.parse(JSON.stringify(objectToClone));

But there is a catch in this solution, this will fail when your object's attribute value is a function.

var a = {name: 'a', exec: function() {return true;}};
var b = JSON.parse(JSON.stringify(a));
console.log(b); // {name: 'a'}

for better insight on cloning, you can refer this article: deep cloning

Rajat Badjatya
  • 760
  • 6
  • 13