javascript에서 shallow copy(얕은 복사), deep copy(깊은 복사)에 대해 알아본다.

배열의 얕은 복사 array.slice()
객체의 얕은 복사 obj.object(target, source)
깊은 복사 JSON.stringify JSON.parse


Reference Copy | 참조 주소 복사

// 배열 복사 : 참조 복사
const arrayA = [1, 2, 3, 4, 5];
const arrayB = arrayA; // 참조값 복사
console.log(arrayA === arrayB); // true, 참조하고 있는 값이 같기 때문에
arrayB[2] = 10;
console.log(arrayA); // [1, 2, 10, 4, 5]
console.log(arrayB); // [1, 2, 10, 4, 5]
// 같은 값을 참조하고 있기 때문에 arrayB를 수정했을 때 arrayA가 바라보고 있는 값도 수정되어있음.

Shallow Copy | 얕은 복사

배열 | array.slice()

const arrayC = [1, 2, 3, 4, 5];
const arrayD = arrayC.slice(); // 복사

console.log(arrayC === arrayD); // false
// slice로 복사본을 만들었기 때문에 두 배열이 참조하고 있는 값은 다름.
arrayD[2] = 10;
console.log(arrayC); // [1, 2, 3, 4, 5]
console.log(arrayD); // [1, 2, 10, 4, 5]
// 복사본을 수정했기 때문에 원본의 수정은 없음.

배열 | [...array]

  • 전개 연산자를 통한 얕은 복사
const arrayK = [1, 2, 3, 4, 5];
const arrayQ = [...arrayK]
console.log(arrayK === arrayQ); // false
// 복사본을 만들었기 때문에 두 배열이 참조하고 있는 값은 다름.
arrayQ[2] = 10;
console.log(arrayK); // [1, 2, 3, 4, 5]
console.log(arrayQ); // [1, 2, 10, 4, 5]

객체 | Object.assign(target, source)

  • 객체 안에 객체나 배열과 같은 참조값이 있을 경우 참조값이 복사됨
  • 객체 안에 객체나 배열과 같은 참조값이 있는 경우가 아니라면 사용해도 무방함
const objA = { class: "user", info: { id: "ABC", age: "30" } };
const objB = Object.assign({}, objA);

console.log(objA === objB); // false
console.log(objA.info === objB.info); // true
// 배열과 마찬가지로 얕은 복사 시, 참조값은 참조 주소를 복사하는 문제

객체 | [...Object]

  • 전개 연산자를 통한 얕은 복사
  • 객체 안에 객체나 배열과 같은 참조값이 있을 경우 참조값이 복사됨
  • 객체 안에 객체나 배열과 같은 참조값이 있는 경우가 아니라면 사용해도 무방함
const objW = { class: "user", info: { id: "ABC", age: "30" } };
const objP = {...objW}
console.log(objW === objP); // false

objP['class'] = 'admin'; 
console.log(objW.class === objP.class); // false
console.log(objW.class); // user
console.log(objP.class); // admin


objP.info.id = "PQW";
console.log(objW.info === objP.info); // true
console.log(objW.info.id === objP.info.id); // true
console.log(objW.info.id); // PQW
console.log(objP.info.id); // PQW

Shallow Copy(얕은 복사)의 문제점

위와 같은 방법으로 복사할 경우,원시값은 새로운 값이 할당되지만
ArrayObject와 같은 참조값의 경우, 참조값이 복사되기 때문에
복사한 값을 수정할 경우 원본도 함께 수정됨.
물론 이를 의도한 경우 문제가 되지 않음

const arrayE = [1, 2, 3, 4, 5, [100, 200], { name: "kim" }];
const arrayF = arrayE.slice();

console.log(arrayE === arrayF); // false
// 원시값의 경우 새로운 값을 할당하지만
console.log(arrayE[5] === arrayF[5]); // true
console.log(arrayE[6] === arrayF[6]); // true
// array나 object와 같은 참조값의 경우 참조주소를 복사

arrayE[5][1] = 300;
console.log(arrayE[5]); // 300
console.log(arrayF[5]); // 300
arrayE[6][name] = "lee";
console.log(arrayE[6][name]); // lee
console.log(arrayF[6][name]); // lee

Deep Copy | 깊은 복사

JSON.stringify & JSON.parse

JSON 형식으로 변환했다가 다시 parse하는 방식으로 완전히 새로운 값을 할당함.

const arrayG = [1, 2, 3, 4, 5, [100, 200], { name: "kim" }];
const arrayH = JSON.parse(JSON.stringify(arrayG));

console.log(arrayG === arrayH); // false
console.log(arrayG[5] === arrayH[5]); // false
console.log(arrayG[6] === arrayH[6]); // false
// 완전히 새로운 값을 할당

// 과정 이해
const process1 = JSON.stringify(arrayG); // JSON type으로 변형(String)
console.log(process1); // "[1,2,3,4,5,[100,200],{"name":"kim"}]"
const process2 = JSON.parse(process1); // JSON parse을 통해 javascript 데이터 타입으로 변형
console.log(process2); // [1, 2, 3, 4, 5, [100, 200], { name: "kim" }]

JSON copy 방식의 한계

JSON.stringify는 function를 처리하지 못함.

const objC = {
  func: function () {
    console.log("err");
  },
};
const objD = JSON.parse(JSON.stringify(objC));

console.log(objC); // {func: ƒ}
console.log(objD); // {}

// 과정 이해
const process1 = JSON.stringify(objC); // JSON type으로 변형(String)
console.log(process1); // {}
const process2 = JSON.parse(process1); // {}
console.log(process2); // {}

jQeury, lodash 활용

이미 잘 만들어진 라이브러리를 활용함.

const jQueryClone = $.extend(true, {}, obj); // jQuery
const lodashClone = _.cloneDeep(obj); // lodash





  • 2021.05.09 - 최초 작성

  • 댓글 환영 질문 환영 by.protect-me

profile
protect me from what i want

0개의 댓글