0

I recall being able to clone an object with the spread operator like such:

let obj1 = {
  key: 'value',
  key2: 'value2'  
}

let obj2 = { ...obj1 }

But now I realize this doesn't work as I am trying to change values of obj2 and its also changing the values in obj1.

If I did:

obj2.key2 = 'test'

It would change obj1.key2 to 'test' as well.

Why is this happening?

I also tried doing:

let obj2 = Object.assign({}, obj1)

but i face the same issues.

Thanks

let obj1 = {
  key1: 'value1',
  key2: 'value2'
}

let obj2 = { ...obj1 }

obj2.key2 = 'changed key2 value'

console.log( obj1.key2 == obj2.key2 )


syn
  • 11
  • 6

3 Answers3

0

First of all, you're only half right. What you're doing is called a "shallow clone", and it copies all properties of an object to another one. Now, if those properties are primitives (numbers / strings), then you can safely change them on one object without altering the other. But for objects or arrays, you're actually copying their reference. So if testKey is an object, when you do obj1.testKey you're referring to the same object as if you do obj2.testKey.

In order to do what's called a "deep clone" so that this doesn't happen, you have 2 options.

Either spread over those objects manually, like this:

let obj1 = {
    key: {
        value: 1
    },
    key2: 2
}

let obj2 = {
    ...obj2,
    key: {
        ...obj1.key
    }
}

This can get really tiring, specially with big structures or more levels of nesting. The second option, which I recommend, is using lodash cloneDeep: https://lodash.com/docs/4.17.11#cloneDeep

SoKeT
  • 590
  • 1
  • 7
  • 16
0

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

syntax:
    Object.assign(target, ...sources)
    target: The target object.
    sources: The source object(s).
    Return value: The target object.
let a = {}
let b = {
  key: 'value',
  key2: 'value2'  
}

Object.assign(a, b)
a.key2 = '123'
console.log(a.key2 == b.key2) // false
// a: {key: "value", key2: "123"}
// b: {key: "value", key2: "value2"}

or

let b = {
  key: 'value',
  key2: 'value2'  
}

let a = Object.assign({}, b)
a.key2 = '123'
console.log(a.key2 == b.key2) // false
// a: {key: "value", key2: "123"}
// b: {key: "value", key2: "value2"}
Jason Liu
  • 31
  • 1
  • 13
-1

The reason is because assign() only creates a reference (pointer) to the original object. So if you change the reference object, you change the original. To completely copy an object, I typically convert the object to JSON and then back to a new object:

let obj1 = {
  key: 'value',
  key2: 'value2'
}

console.log("Ojbect 1, key:" + obj1.key);

let obj2 = JSON.parse(JSON.stringify(obj1));

obj2.key = "new_value";

console.log("Object 1, key:" + obj1.key);
console.log("Object 2, key:" + obj2.key);
Jay
  • 353
  • 4
  • 8
  • Wow, ok. Mind explaining why I was downvoted? – Jay Apr 19 '19 at 02:24
  • This is not a good solution, as it's quite slower than simply iterating the object recursively to perform a deep clone. Also, if any of the properties are not serializable, your "clone" will not be an exact copy of the original. For example, if you have an object like `{ date: new Date() }` – SoKeT Apr 19 '19 at 02:24
  • @CertainPerformance According to [this](http://jsben.ch/bWfk9), lodash deep clone is faster. – SoKeT Apr 19 '19 at 03:19