[위클리페이퍼] 얕은 복사와 깊은 복사

nali kang·2024년 1월 20일
0

위클리페이퍼

목록 보기
6/13
post-thumbnail

참조타입의 복사

변수 선언 시 참조타입은 기본적으로 메모리의 주소를 가지고있다. 때문에 기본적으로 변수 복사 시 데이터가 아닌 메모리의 주소를 가져온다. 때문에 원본의 데이터를 수정하더라도 같은 주소를 가지고있는 복사본이 같이 수정이 되는등 복사방식에 따른 데이터착오가 발생할 수 있다. 관련하여 복사의 종류에 대해 알아보려 한다.


참조 복사(Copy)의 종류

참조타입의 복사는 얕은 복사(Shallow copy)와 깊은 복사(Deep Copy)로 나뉜다. 기본적으로 원본을 변수에 직접 주입하는것이 얕은 복사라 할 수 있는데 이때 참조 타입의 경우 데이터를 복사하는 것이 아닌, 데이터가 저장된 메모리의 주소값을 복사하게 된다. 반대로 깊은 복사는 새로운 메모리를 할당하여 얻은 주소값을 이용하여 데이터 자체를 복사한다.

얕은 복사 (Shallow Copy)

const temp = {test: 'test'}; // temp의 주소예시 22b03
const comp = temp; // temp의 주소를 복사 - comp의 주소는 22b03

temp.test = 'test123'; // 주소 22b03 메모리의 값을 test123으로 수정

console.log(temp); // {test: 'test123'} > 22b03의 값
console.log(comp); // {test: 'test123'} > 22b03의 값

console.log(comp === temp); // true > 22b03 === 22b03

위 상황은 temp라는 원본 객체를 comp라는 복사본에 얕은 복사를 진행한 내용이다.
주석에 써놓은 내용과 같이 데이터를 복사하는것이 아닌 메모리의 주소값을 복사하여 사용하기 때문에 원본이 수정되면 복사본또한 수정(반대의 경우도 마찬가지)된다.

깊은 복사 (Deep Copy)

깊은 복사를 하는 방법은 여러가지가 있다.

const comp = {a:'1', b:'2'}; // 주소 예시 430ac

// Json을 이용하여 객체를 String 문자열로 변경
// 그 후 변경된 String을 다시 Json 객체로 변경
// 변경된 값을 저장 (주소가 아닌 데이터 자체를 복사)
const temp1 = JSON.parse(JSON.stringify(comp)); // 주소 예시 5c13a

const temp2 = isCopyObj(comp); // 주소 예시 8230b

// 데이터 한개씩을 새롭게 저장
// 새로 저장한 값을 return (주소가 아닌 데이터 자체를 복사)
function isCopyObj(origin) {
    let res = {};

    for (let key in origin) {
      if (typeof origin[key] === 'object') {
          res[key] = isCopyObj(obj[key]);
      } else {
          res[key] = origin[key];
      }
    }

    return res;
}

console.log(comp === temp1) // false > 430ac === 5c13a
console.log(comp === temp2) // false > 430ac === 8320b

위 예시처럼 Json을 이용하거나 내부 반복문을 통해 깊은복사가 가능하다.

Spread Operator

복사하는 방법에는 스프레드 연산자(Spread Operator)가 있는데 이 경우는 약간 특수한 경우라 할 수 있다.
스프레드 연산자는 객체의 프로퍼티를 빠르게 복사할 수 있는 방법으로 사용법은 매우 간단하다.

const comp = { a: '1', b: { c: '3'}};
const temp = {...comp};

위와 같이 사용할 수 있는데 이때 스프레드 연산자는 깊은 복사처럼 새로운 주소에 데이터를 할당한다.
그렇다면 스프레드 연산자는 깊은 복사일까?

참고: Spread 문법은 배열을 복사할 때 1 레벨 깊이에서 효과적으로 동작합니다. 그러므로, 다음 예제와 같이 다차원 배열을 복사하는것에는 적합하지 않을 수 있습니다. (Object.assign() 과 전개 구문이 동일합니다)
출처 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax

참고 내용과 같이 1depth에서만 깊은 복사가 진행된다고 한다.

위 예시의 경우 comp의 프로퍼티 ab 데이터만 그대로 가져오게 되는데, b는 객체안의 객체로 1depth를 넘어가기 때문에 b객체 안의 데이터는 복사되지 않고 b가 실제로 가지고있는 데이터인 메모리의 주소값을 복사하게 된다. 따라서 아래와 같은 결과가 나타난다

comp.a = '111';
comp.b.c = '333';

console.log(comp === temp); // false
console.log(comp.a === temp.a); // false > comp.a = '111', temp.a = '1'
console.log(comp.b === temp.b); // true
console.log(comp.b.c === temp.b.c); // true

때문에 완전한 깊은 복사를 하기 위해서는 Json을 이용하거나 반복문을 이용해 내부 데이터를 복사해야한다.

참조

https://cocobi.tistory.com/156
https://velog.io/@yukyung/Spread-Operator%EB%8A%94-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC%EC%9D%BC%EA%B9%8C-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC%EC%9D%BC%EA%B9%8C
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax

profile
안녕하세요 강나리입니다.

0개의 댓글

관련 채용 정보