[JS]얕은 복사(Shallow Copy) vs 깊은 복사(Deep Copy)

KBS·2022년 1월 13일
0

JS

목록 보기
7/9


기술면접으로 나온 내용중 얕은복사와 깊은복사에 대해 정리하려고 한다.

얕은 복사(Shallow Copy) vs 깊은 복사(Deep Copy

자료형의 값 복사(깊은 복사)

자바스크립트는 기본 자료형(숫자, 문자열, boolean)의 값을 복사할 때 값을 완전히 복사한다. 따라서 =을 이용하여 값 복사를 쉽게 할 수 있다.

let originalValue = 100;
let newValue = originalValue;

originalValue = 200;

console.log(originalValue);
console.log(newValue);

위 소스코드 1열에서 originalValue에 100의 값이 들어가고, 2열에서 newValue에 100이라는 값이 복사되어, 아래 그림과 같이 두개의 변수 OriginalValue, NewValue는 완전히 독립적인 상태가 된다.

이 상태에서 4열에 따라 originalValue의 값을 200으로 변경하면, originalValue 값만 200이 된다.
이렇게 두 변수가 완전히 독립성을 갖는 것을 '값 복사' 또는 '깊은 복사'라고 한다.
값을 복사하고 변경했을 때, 다른 값에 전혀 영향을 주지 않는다.

객체의 참조 복사(얕은복사)

객체에 변수를 저장하면, 실제 값을 저장하는 것이 아니라 객체를 메모리 어딘가에 만들고, 객체의 참조(위치값)를 저장하게 된다.
따라서 객체(배열 포함)의 경우 =를 이용하여 복사하면, 참조 복사만 가능하다.

let originalArray = [1,2,3,4];
let newArray = originalArray;

originalArray[0] = 200;

console.log(originalArray);
console.log(newArray);

1열에서 배열 originalArraydp [1,2,3,4]를 저장하는 과정은 다음과 같다.
주소값 0x10에 [1,2,3,4]를 저장하고, 객체 originalArray는 '0x10'위치를 참조.

이때 2열에 따라 참조되는 위치값 '0x10'이 복사된다.

4열에서 originalArray[0]=200;을 실행하면, 참조되는 위치 0x10의 값이 변경된다.
originalArray와 newArray는 같은 메모리 위치를 참조하게 된다.

따라서 두 배열은 독립적이지 않다. 이것을 '참조 복사' 또는 '얕은 복사'라고 한다.

6,7열에 따라 newArray[0]을 출력하면 둘 다 200을 출력한다.

얕은 복사(Shallow Copy)란?

const obj1 = {a: 1, b: 2};
const obj2 = obj1;

console.log(obj1 === obj2); // true
  • 위의 예시처럼 객체를 직접 대입하는 경우 참조에 의한 할당이 이루어지므로 둘은 같은 데이터(주소)를 가지고 있다.
  • 이것이 얕은 복사이다.
const obj1 = { a:1, b:2};
const obj2 = obj1;

obj2.a = 100;

console.log( obj1.a ); // 100

-위 두 객체는 같은 데이터(주소)를 가지고 있고, 그래서 같은 주소를 참조하고 있다. 따라서 obj2의 property를 수정하고, obj1를 출력해도 obj2값과 동일하다.

깊은 복사(Deep Copy)란?

얕은 복사 처럼 주소를 복사하여 공유하는것이 아니라, 새로운 객체안 속성만 복사해서 사용하는것.

방법1 spread(...)연산자를 통한 복사

const obj1 = {a:1, b:2};
const obj2 = {...obj};

obj2.a = 100;

console.log(obj1 === obj2) // false
console.log(obj1.a) //1
  • spread(...)연산자를 통해 {} 안에 obj1의 속성을 복사하여 obj2에 할당하였다.
    -obj1과obj2는 다른 주소를 갖게 되었다. 하지만 1depth까지만 해당된다.

방법2. Object.assign()메소드를 통한 복사

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Object.assign()메소드 사용법(MDN)

const obj1 = { a:1, b:2 };
const obj2 = Object.assign({}, obj1);

obj2.a = 100;

console.log( obj1 === obj2 ) // false
console.log( obj1.a) //1

-Object.assign() 메소드를 통해 첫 번째 인자로 {}객체를, 두 번째 인자로 obj1 넣고 obj2에 할당

  • obj1과 obj2는 다른 주소를 갖게 되었다. (1depth까지만)

깊은 복사의 함정

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

  • Object.assign() 메소드와 spread 연산자 둘 다 완벽한 Deep Copy가 되지 않는다
  • 객체가 서로 다르다고 깊은 복사가 이루어진건 아니다.
  • 1 depth까지는 확실하게 Deep Copy
  • 2 depth 이상이면 Shallow Copy

spread(...)연산자를 이용해 depth2까지 복사하는 방법

const obj1 = { a: {b:1, c:1}, d:2};
const obj2 = { ...obj1, a:{...obj1.a} };

obj1.a.b = 100;

console.log(obj1 === obj2) //false
console.log(obj2.a.b) // 1

다른 방법들.

  • 재귀적으로 깊은 복사 수행
  • Lodash의 cloneDeep 함수 사용 ex)예시
function clone(obj) {
	let output = {};
    for(let i in obj{
    	output[i] = obj[i];
    }
    return output;
}

let original = {a: 10, b: 20}; // 원본 객체
let regerenced = original; // 얕은 복사 객체
let cloned = clone(original) // 깊은 복사 객체

original.a = 20;

console.log(JSON.stringfy(referenced, null, 2));
console.log(JSON.stringfy(cloned, null, 2));
  • JSON.parse()와 JSON.stringfy()함수 사용

끝.

해당 내용은 아래의 링크에서 참조하였다.
https://hanamon.kr/javascript-shallow-copy-deep-copy/
https://wanna-b.tistory.com/18

profile
FE DEVELOPER

0개의 댓글