요약
- 객체를 프로퍼티 값으로 갖는 객체의 경우 얕은 복사는 한단계까지만 복사하는것을 말하고 깊은 복사는 객체에 중첩되어있는 객체까지 모두 복사해서 원시값처럼 완전한 복사본을 만드는것을 말합니다.
- 원시값을 할당한 변수를 다른 변수에 할당하는것을 깊은 복사, 객체를 할당한 변수를 다른 변수에 할당하는것을 얕은 복사라고 부르는 경우도 있습니다.
- 원시 값과는 다르게 객체는 여러개의 식별자가 하나의 객체를 참조할수있습니다.
- 얕은 복사를 하는방법으로는 스프레드 연산자를 사용하거나 Array.prototype.slice() 메서드를 사용하는 방법이 있습니다.
- 깊은 복사를 하는 방법으로는 JSON.parse 와 JSON.stringify 메서드를 사용하거나 재귀함수 구현, Lodash 라이브러리를 사용하는 방법이 있습니다.
원시값과 참조 타입에 대한 꼬리질문은 밑의 페이지를 참고할것
얕은 복사 방법
얕은 복사란 객체 안에 객체가 있을경우 한 개의 객체라도 기존 변수의 객체를 참조하고 있다면 얕은복사입니다.
Array.prototype.slice()
start부터 end 인덱스까지 기존 배열에서 추출하여 새로운 배열을 리턴하는 메서드, 만약 start와 end를 설정하지 않는다면 기존 배열을 전체 얕은 복사합니다.
const arr = [ 1, 2, 3, [4, 5]] const copyArr = arr.slice(); checker(arr, copyArr) //true checker(arr, copyArr) //true
Spread 연산자
중첩된 구조의 배열은 불변성을 지키지 못하며 복사한다.
const arr = [ 1, 2, 3, [4, 5]] const copyArr = [...arr] checker(arr, copyArr) //true copyArr[3].push(7) console.log(copyArr)//[ 1, 2, 3, [ 4, 5, 7 ] ] checker(arr, copyArr)//true
Object.assign
const arr = [1, 2, [3, 4]]; const copyArr = Object.assign([], arr); checker(arr, copyArr); //true copyArr[2].push(5); checker(arr, copyArr) //true
깊은 복사 방법
깊은 복사된 객체는 객체 안에 객체가 있을 경우에도 원본과의 참조가 완전히 끊어진 객체를 말합니다.
JSON.parse && JSON.stringify
JSON.stringify()는 객체를 문자열로 변환하는데 이 과정에서 원본 객체와의 참조가 모두 끊어집니다.
객체를 json 문자열로 변환 후, JSON.parse()를 이용해 다시 원래 객체(자바스크립트 객체)로 만들어줍니다.
이 방법이 가장 간단하고 쉽지만 다른 방법에 비해 느리다는 것과 객체가 function일 경우, undefined로 처리한다는 것이 단점입니다.
const object = { a: "a", number: { one: 1, two: 2, }, arr: [1, 2, [3, 4]], }; const copy = JSON.parse(JSON.stringify(object)); copy.number.one = 3; copy.arr[2].push(5); console.log(object === copy); // false console.log(object.number.one === copy.number.one); // false console.log(object.arr === copy.arr); // false console.log(object); // { a: 'a', number: { one: 1, two: 2 }, arr: [ 1, 2, [ 3, 4 ] ] } console.log(copy); // { a: 'a', number: { one: 3, two: 2 }, arr: [ 1, 2, [ 3, 4, 5 ] ] }
재귀 함수
복잡해서 잘 안쓰이는 방법입니다.
const object = { a: "a", number: { one: 1, two: 2, }, arr: [1, 2, [3, 4]], }; function deepCopy(object) { if (object === null || typeof object !== "object") { return object; } // 객체인지 배열인지 판단 const copy = Array.isArray(object) ? [] : {}; for (let key of Object.keys(object)) { copy[key] = deepCopy(object[key]); } return copy; } const copy = deepCopy(object); copy.number.one = 3; copy.arr[2].push(5); console.log(object === copy); // false console.log(object.number.one === copy.number.one); // false console.log(object.arr === copy.arr); // false console.log(object); // { a: 'a', number: { one: 1, two: 2 }, arr: [ 1, 2, [ 3, 4 ] ] } console.log(copy); // { a: 'a', number: { one: 3, two: 2 }, arr: [ 1, 2, [ 3, 4, 5 ] ] }
Lodash 라이브러리 사용
쉽고 편하게 복사할수있습니다.
단점 : 코딩 테스트에서 못씁니다.
const deepCopy = require("lodash.clonedeep") const object = { a: "a", number: { one: 1, two: 2, }, arr: [1, 2, [3, 4]], }; const copy = deepCopy(object); copy.number.one = 3; copy.arr[2].push(5); console.log(object === copy); // false console.log(object.number.one === copy.number.one); // false console.log(object.arr === copy.arr); // false console.log(object); // { a: 'a', number: { one: 1, two: 2 }, arr: [ 1, 2, [ 3, 4 ] ] } console.log(copy); // { a: 'a', number: { one: 3, two: 2 }, arr: [ 1, 2, [ 3, 4, 5 ] ] }