const obj1 = { a: 1, b: 2};
const obj2 = obj1;
console.log( obj1 === obj2 ); // true
배열 내장 메서드인 slice()를 사용하면 원본 배열을 복사할 수 있다.
let arr = [0, 1, 2, 3];
let copiedArr = arr.slice();
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
새롭게 생성된 배열은 원본 배열과 같은 요소를 갖지만 참조하고 있는 주소는 다르다.
주소가 다르기 때문에 복사한 배열에 요소를 추가해도 원본 배열에는 추가되지 않는다.
copiedArr.push(4);
console.log(copiedArr); // [0, 1, 2, 3, 4]
console.log(arr); // [0, 1, 2, 3]
spread라는 단어의 뜻처럼 배열을 펼칠 수 있다. 펼치는 방법은 배열이 할당된 변수명 앞에 ... 을 붙여주면 된다. 배열을 펼치면 배열의 각 요소를 확인할 수 있다.
배열뿐만 아니라 객체를 복사할 때도 사용할 수 있다.
그러나 참조 자료형 내부에 참조 자료형이 중첩되어 있는 경우, slice(), Object.assign(), spread syntax를 사용해도 참조 자료형 내부에 참조 자료형이 중첩된 구조는 복사할 수 없다. 참조 자료형이 몇 단계로 중첩되어 있던지, 위에서 설명한 방법으로는 한 단계까지만 복사할 수 있다.
let arr = [0, 1, 2, 3];
console.log(...arr); // 0 1 2 3
et arr = [0, 1, 2, 3];
let copiedArr = [...arr];
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
소스 개체에서 대상 개체로 모든 열거 가능한 속성과 자체 속성을 복사, 대상 객체를 반환.
소스 개체의 getter와 대상의 setter를 호출, 새 속성을 복사하거나 정의하지 않고 속성만 할당.
let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = Object.assign({}, obj);
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false
JSON.stringify()는 참조 자료형을 문자열 형태로 변환하여 반환하고, JSON.parse()는 문자열의 형태를 객체로 변환하여 반환. 먼저 중첩된 참조 자료형을 JSON.stringify()를 사용하여 문자열의 형태로 변환하고, 반환된 값에 다시 JSON.parse()를 사용하면, 깊은 복사와 같은 결과물을 반환.
const arr = [1, 2, [3, 4]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
간단하게 깊은 복사를 할 수 있는 것처럼 보이지만, 이 방법 또한 깊은 복사가 되지 않는 예외가 존재한다. 대표적인 예로 중첩된 참조 자료형 중에 함수가 포함되어 있을 경우 위 방법을 사용하면 함수가 null로 바뀌게 되고 따라서 이 방법 또한 완전한 깊은 복사 방법이라고 보기 어렵다.
const arr = [1, 2, [3, function(){ console.log('hello world')}]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, function(){ console.log('hello world')}]]
console.log(copiedArr); // [1, 2, [3, null]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
완전한 깊은 복사를 반드시 해야 하는 경우라면, node.js 환경에서 외부 라이브러리인 lodash, 또는 ramda를 설치, lodash와 ramda는 각각 방법으로 깊은 복사를 구현.
const lodash = require('lodash');
const arr = [1, 2, [3, 4]];
const copiedArr = lodash.cloneDeep(arr);
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false
lodash의 cloneDeep을 사용한 깊은 복사의 예시