[JS] 얕은 복사? 깊은 복사?

김하영·2022년 11월 26일
0

Javascipt

목록 보기
5/11
post-thumbnail

자바스크립트에서 얕은 복사, 깊은 복사란 '객체를 복사하는 방법'을 말한다.

얕은 복사와 깊은 복사에 대해 이해하기 위해서는 먼저 자바스크립트의 데이터 타입에 대한 이해가 필요하다.
복사는 어떤 데이터 타입인지에 따라 다르게 진행되기 때문이다.
자바스크립트에서 사용되는 데이터들은 크게 원시값참조값으로 나뉜다.

원시값

변경 불가능한 값 (immutable value)

  • Number
  • String
  • Boolean
  • Null
  • Undefined

참조값

변경 가능한 값 (mutable value)

  • Object
  • Symbol

변수에 값을 저장한다면?

const a = 10; // a에는 10이 담긴다.

변수에 원시 값을 담는다면 '값' 자체가 담긴다.

const a = { 
	name: 'yj',
    age: 9
}  // a에는 주소가 담긴다.

반면, 변수에 객체를 담는다면 객체 값이 아니라, 객체 값이 저장된 '메모리 주소'가 담긴다.

변수를 비교한다면?

const a = {
	name: 'hayeong',
    age: 26
};

const b = {
	name: 'hayeong',
    age: 26
};

원시 타입인 변수끼리 비교한다면, 값 자체를 비교하고,
객체 타입인 변수끼리 비교한다면, 참조 값을 비교한다.

console.log(a === b); // false : 각각 객체를 할당했기 때문에 참조 값이 다름
console.log(a.name === b.name);  // true : 값 자체 비교

원시값은 값을 복사할 때 복사된 값을 다른 메모리에 할당하기 때문에 원래의 값과 복사된 값이 서로에게 영향을 미치지 않는다.

const a = 1;
let b = a;

b = 2;

console.log(a); // 1
conosle.log(b); // 2

하지만 참조값은 변수가 객체의 주소를 가리키는 값이기 때문에 복사된 값(주소)이 원래의 값과 같은 값을 가리킨다. (== 얕은 복사)

const a = {number: 1};
let b = a;

b.number = 2;

console.log(a); // {number: 2}
console.log(b); // {number: 2}

이러한 객체의 특징 때문에 객체를 복사하는 방법을 두 가지로 나누어 볼 수 있는 것이다.


Javascript의 복사

우선, 일반적으로 우리가 가장 많이하는 형태의 복사를 살펴보자.

const a = {name: 'hayeong'};
const b = a;

위의 예시에서 변수(a)와 할당해서 만든 변수(b)는 같은 주소를 참조하고 있다. (= 같은 참조 값을 가지고 있다.)
그렇기 때문에, a와 b 둘 중 무엇이든 데이터를 조작하게 되면 a와 b 모두 동일하게 변경된다.

이렇게 참조만 하게 되는 복사는 원치않는 결과를 가져올 수 있기 때문에, 상황에 따라 얕은 복사와 깊은 복사를 사용할 줄 알아야 한다.

얕은 복사

얕은 복사(Shallow Copy)란 객체를 복사할 때 원래값과 복사된 값이 같은 참조를 가리키고 있는 것을 말한다.
객체안에 객체가 있을 경우 한개의 객체라도 원본 객체를 참조하고 있다면 이를 얕은 복사라고 한다.
다음은 얕은 복사를 하는 방법이다.

1. Object.assign()

Object.assign은 첫 번째 요소로 들어온 객체에 다음 인자로 들어온 객체를 복사해준다.

const obj = {
	a: 1,
    b: {
    	c: 2
    }
};

const copiedObj = Object.assign({}, obj);

copiedObj.b.c = 3

obj === copiedObj // false
obj.b.c = copiedObj.b.c  // true

2. 전개연산자 spread operator

const obj = {
	a: 1,
    b: {
    	c: 2
    }
};

const copiedObj = {...obj};

copiedObj.b.c = 3;

obj === copiedObj;  // false
obj.b.c === copiedObj.b.c;  // true

깊은 복사

깊은 복사(Deep Copy)된 객체는 객체 안에 객체가 있을 경우에도 원본과의 참조가 완전히 끊어진 객체를 말한다.

1. 재귀함수를 이용한 복사

const obj = {
	a: 1,
    b: {
    	c: 2,
    }
};

function copyObj(obj) {
	const result = {};
    
    for (let key in obj) {
    	if (typeof obj[key] === 'object') {
        	result[key] = copyObj(obj[key]);
        } else {
        	result[key] = obj[key];
        }
    }
    
    return result;
}

const copiedObj = copyObj(obj);

copiedObj.b.c = 3;

obj.b.c === copiedObj.b.c; // false

JSON.stringify()

JSON.stringify()는 객체를 json 문자열로 변환하는데 이 과정에서 원본 객체와의 참조가 모두 끊어진다. 객체를 json 문자열로 변환후 JSON.parse()를 이용해 다시 자바스크립트 객체로 만들어주면 깊은 복사가 된다.
하지만 이 방법은 사용하기는 쉽지만 다른 방법에 비해 아주 느리다고 알려져있다.

const obj = {
	a: 1,
    b: {
    	c: 2
    }
};

const copiedObj = JSON.parse(JSON.stringify(obj));

copiedObj.b.c = 3;

obj.b.c === copiedObj.b.c  // false

라이브러리 사용

lodash 라이브러리를 사용하면 깊은 복사를 더 쉽게 할 수 있다.

const obj = {
	a: 1,
    b: {
    	c: 2
    }
};

const copiedObj = _.cloneDeep(obj);

copiedObj.b.c = 3;

obj.b.c === copiedObj.b.c // false

결론

결론적으로 자바스크립트에서 얕은 복사, 깊은 복사는 데이터 타입 중 객체를 복사하는 방법을 말하는 것이다. 두 방식의 차이점은 원본 데이터에 영향을 주느냐, 안주느냐 인데 일반적인 방식으로 객체를 복사하면 '얕은 복사'하게 되는 것이다.

profile
호기심 많은 프론트엔드 주니어 💡

0개의 댓글