let arr = [1, 2, 3, 4, 5]; let copyArr = [].concat(arr); arr[0] = 0; console.log(copyArr[0]) // 1(바뀌지 않음)
primitive type이 immutable한 것은, 복사해오기 때문이다. 따라서 복사본을 수정해도 원본은 그대로 남아있게 된다. 반면 object, array는 단순히 복사하는 것이 아니라 주소를 참조하기 때문에 원본도 바뀌게 된다. 바뀌지 않게 하려면 primitve type이 하듯이 복사하는 방법을 사용한다.
- Shallow Copy
let obj = {a: 1, b: 2, c: 3}; let clone = Object.assign({}, obj); let clone2 = {...obj}; obj.c = 5; console.log(clone.c) // 3 (바뀌지 않음) console.log(clone2.c) // 3
let obj = {a: 1, b: 2, c: {deep: 'try and copy me'}}; let clone = Object.assign({}, obj); let clone2 = {...obj}; obj.c.deep = 'hahaha'; console.log(clone.c) // {deep: 'hahaha'} (바뀜) console.log(clone2.c) // {deep: 'hahaha'}
프로퍼티로 또다른 object를 가졌을 때 그 object는 다른 주소를 갖게 된다. clone을 해와도 여전히 그 주소를 참조하게 되므로, 원본도 클론도 같은 주소의 값을 참조하고, 결국 mutable하게 된다.
let obj = {a: 1, b: 2, c: {deep: 'try and copy me'}}; let clone = Object.assign({}, obj); let clone2 = {...obj}; let superClone = JSON.parse(JSON.stringify(obj)); obj.c.deep = 'hahaha'; console.log(clone.c) // {deep: 'hahaha'} (바뀜) console.log(clone2.c) // {deep: 'hahaha'} console.log(superClone.c) // {deep: 'try and copy me'}
JSON을 사용하면 deep copy가 가능하다. 그러나 만약 원본 객체의 크기가 엄청나게 크다면 위 방식을 사용할 경우 copy하는데 시간이 오래 걸릴 수 있으므로 주의해야한다.