티스토리 뷰

개요

이전 발표했던 내용을 이해하기 위해 깊은 복사와 얕은 복사에 대해 찾아보았고, 몇몇 좋은 블로그 글이 있어 참고하여 글을 정리하였다.

 

https://blog.devgenius.io/javascript-shallow-copy-deep-copy-287e19d64e92

https://medium.com/version-1/cloning-an-object-in-javascript-shallow-copy-vs-deep-copy-fa8acd6681e9

 

내용

프로그래밍에서 복사란 무엇일까?

프로그래밍에선 값을 변수에 저장하는데, 복사본을 만든다는 것은 동일한 값으로 새로운 변수를 만든다는 것을 의미한다.

 

기본 데이터 유형

  • Number - 정수 또는 부동 소수점 숫자
  • String - 텍스트 값을 나타내는 문자열
  • Boolean - true & false
  • undefined - 값이 정의되지 않은 최상위 속성
  • null - null 값을 나타내는 특수 키워드
  • BigInt - 임의의 정밀도를 가진 정수
  • Symbol - 인스턴스가 고유하며 변경할 수 없는 데이터 유형

 

기본 데이터 유형을 복사한다면?

let a = 1;
let n = a;

a = 13;

console.log(a); // 13
console.log(n); // 1

예제 코드를 실행하면 a의 복사본인 n이 생성되고, a에 새 값을 재할당하면 a의 값은 변경되지만 b의 값은 변경되지 않는다.

기본 데이터 유형을 복사를 하면 프린터기로 같은 것을 복사하여 뽑아내는 것과 같이 복사가 된다.

 

비원시 / 복합 데이터 유형

  • Object
    • 속성의 모음.
    • 속성은 키 값을 사용하여 식별.
    • 복잡한 데이터 구조를 구축할 수 있는 다른 개체를 포함하여 모든 유형의 값이 될 수 있음.

 

비원시 / 복합 데이터 유형을 복사한다면?

 

let test = {
	a : 1,
};

let copyTest = test;

copyTest.a = 11;

console.log(test.a); // 11
console.log(copyTest.a) // 11

 

객체는 인스턴스화 될 때 한번만 저장되며 변수를 할당할 경우 해당 값에 대한 포인터(참조)가 생성된다.

위의 예제 코드의 test와 copyTest는 각각 다르게 동작할것이라 예상할 수도 있으나 포인터(참조) 값을 통하여 복사본을 만들기 때문에 copyTest.a의 값을 바꾸면 test.a의 값에도 영향이 미친다.

 

얕은 복사란?

복사된 개체의 속성이 원본 개체의 속성과 동일한 참조를 공유하는 복사본이다.

결과적으로 소스나 복사본을 변경하면 다른 개체도 변경될 수 있기에 의도치 않게 소스나 복사본이 변경될 수 있다.

얕은 복사는 객체의 비트 단위 복사이다.

객체의 얕은 복사본을 만드는 경우 기본 유형 값이 복사되고 기본/참조 유형이 아닌 경우 메모리 주소가 복사된다.

 

얕은 복사를 하는 방법

1. 스프레드 연산자를 통한 얕은 복사
    let test = {
        a:1,
        test2: { num: 1 },
    }

    let b = {...test};
    b.a = 3;
    b.test2.num = 3;
    
    console.log(test); // { a:1, test2: {num: 3} }
    console.log(b); // { a:3, test2: {num: 3} }



2. Object.assign을 통한 얕은 복사
    let test = {
        a:1,
        test2: { num: 1 },
    }

    let b = Object.assign( {}, test);
    b.a = 3;
    b.test2.num = 3;
    
    console.log(test); // { a:1, test2: {num: 3} }
    console.log(b); // { a:3, test2: {num: 3} }

 

  • 복제된 객체의 첫 번째 수준에서 속성을 업데이트 하면 원래 속성은 업데이트 되지 않는다.
  • 더 깊은 수준의 속성을 업데이트 하면 원래 속성도 업데이트 된다.
    • 이런 일이 생길 수 있는 이유는 더 깊은 수준의 속성은 복사되는 것이 아닌 참조되는 것이기 때문이다.

 

깊은 복사

원본 개체와 복사본을 만든 소스 개체의 속성이 동일한 참조(기본 값)를 공유하지 않는 복사본이다.

원본이나 복사본을 변경할 때 다른 개체도 변경되지 않게 보장할 수 있기 때문에 실수로 인한 값 변경이 일어나지 않는다.

 

깊은 복사는 모든 필드를 복사하고 모든 참조 유형 값에 새 메모리 주소를 할당한다.

 

깊은 복사를 하는 방법

1. JSON.stringify에 개체를 전달 후 JSON.parse를 통해 복사하는 방법.
    let test = {
        a:1,
        test2: { num: 1 },
    }

    let b = JSON.parse(JSON.stringify(test));
    
    b.a = 3;
    b.test2.num = 3;

    console.log(test); // { a:1, test2: {num: 1} }
    console.log(b); // { a:3, test2: {num: 3} }
    
    

2. jQuery를 통한 확장 방법.
	const jQuery = require("jquery");
    
    let test = {
        a:1,
        test2: { num: 1 },
    }

    let b = jQeury.extend(true, {}, test)
    
    b.a = 3;
    b.test2.num = 3;

    console.log(test); // { a:1, test2: {num: 1} }
    console.log(b); // { a:3, test2: {num: 3} }
    
    
    
3. jQuery를 통한 확장 방법.
	const _ = require("lodash");
    
    let test = {
        a:1,
        test2: { num: 1 },
    }

    let b = _.cloneDeep(test)
    
    b.a = 3;
    b.test2.num = 3;

    console.log(test); // { a:1, test2: {num: 1} }
    console.log(b); // { a:3, test2: {num: 3} }

 

  • 복제된 객체의 첫 번째 수준에서 속성을 업데이트하면 원래 속성이 업데이트 되지 않는다.
  • 더 깊은 수준의 속성을 업데이트하면 원래 속성은 업데이트 되지 않는다.
    • 이 경우 더 깊은 수준의 속성도 복사되기 때문에 이런 일이 발생한다.

 

결론

javascript에서 깊은 복사와 얕은 복사의 차이점을 이해하는 것은 효율적이고 버그 없는 코드를 작성하는데 필수적이다.

데이터가 어떻게 저장되고 조작되는지 알고있다면 예기치 않은 동작을 방지하고 성능을 향상시킬 수 있기 때문이다.

ECMAScript 6에서 변수 할당과 관련하여 let 변수 키워드를 도입한  것은 변수가 선언된 코드 블록 내에서만 접근할 수 있기 때문에 변수 범위가 제한되어 있으므로 깊은 복사인지 얕은 복사인지에 대한 혼동을 방지할 수 있다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함