본문 바로가기

Coding/TIL (Today I Learned)

JavaScript 얕은 복사 vs 깊은 복사

처음 MDN에서 공부를 할 때 이해되지 않는 부분 투성이었지만, 그 중에서도 얕은 복사와 깊은 복사의 의미를 알지 못하고 알고리즘 퀴즈를 풀기에 급급했다. 프로토타입을 공부하면서 약간 알 것 같은 상태가 되었는데, 프로토타입의 개념이 간단하지 않기 때문에 그 과정에서 알게 된 복사의 두 가지 개념을 우선 정리해 보기로 했다.

잘못된 게 있다면 누구든 알려주시길 바라요.

 

레퍼런스 : 

제로초TV https://youtu.be/BSReDRBjbp0

모던자바스크립트 입문

 


영어로는 얕은 복사(shallow copy), 깊은 복사(deep copy) 라고 표현 하는데 둘을 간단히 구분하면,

얕은 복사 : 참조

깊은 복사 : 복사

 

원시타입(문자, 숫자, 논리값)은 복사(깊은복사)가 되고

원시타입을 제외한 객체들(배열, 오브젝트, 함수)은 참조(얕은복사)가 된다.

즉 데이터의 타입에 따라 다루는 방법이 다르다. 비교해서 코드를 써보면,

let a = 100; //숫자는 원시타입
let b = a; //이것은 복사 입니다.

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

//여기서 a를 변경하면,
a = 200;

console.log(a); //200 a의 값만 변경됨.
console.log(b); //100 
let a = { name: '하루'};
let b = a; //이것은 객체이므로 참조가 됩니다.

console.log(a); //{name: "하루"}
console.log(b); //{name: "하루"}

//a의 값을 변경하게 되면,
a.name = '바보';

console.log(a); //{name: "바보"}
console.log(b); //{name: "바보"} b도 영향을 받게 된다는 것!

 

그럼 객체는 깊은 복사를 할 수 없는걸까?

몇 가지 복잡한 방법들이 있지만 말 그대로 복잡하거나 성능이 나쁜 이슈가 있다고 한다.

 

간단하게 복사하는 방법으로 한 가지는 Object.keys()를 활용하는 것. 하지만 이것도 하위 객체가 존재하면 그 안에서는 먹히지 않은 불완전한 복사 방법이다.

let obj1 = { a: 1, b: 2, c: { d: 3}} //이렇게 뎁스를 가진 객체의 경우
let obj2 = {}; //내용을 복사할 빈 갠체를 만들고

//Object.keys()메서드로 키 값을 복사
Object.keys(obj1).forEach(function(key) {
obj2[key] = obj1[key];
});

console.log(obj1); //{ a: 1, b: 2, c: { d: 3}}
console.log(obj2); //{ a: 1, b: 2, c: { d: 3}}

obj1.a = 0; //obj1의 a값을 0으로 변경하면

console.log(obj1.a); //0 이 경우 1 단계 데이타들은 복사되어 obj1의 값만 변경됨
console.log(obj2.a); //1

obj1.c.d = 4; //하지만 obj1의 d값을 변경하면

console.log(obj1.c.d); //4 
console.log(obj2.c.d); //4 obj2의 d값도 변경이 된다!!

 

뎁스를 극복하기 위해 JSON.parse(), JSON.stringify() 메서드를 활용할 수 있는데 성능이슈가 크기 때문에 실무에서는 피한다고..

let obj1 = { a: 1, b: 2, c: { d: 3}};

let obj2 = JSON.parse(JSON.stringify(obj1));

console.log(obj1); //{ a: 1, b: 2, c: { d: 3}}
console.log(obj2); //{ a: 1, b: 2, c: { d: 3}}

obj1.c.d = 4; //위와 동일한 방법으로 d값을 바꾸면

console.log(obj1); //{ a: 1, b: 2, c: { d: 4}} obj1만 변경됨
console.log(obj2); //{ a: 1, b: 2, c: { d: 3}}

 

객체의 뎁스가 깊어질수록 헷갈릴 것 같다. 다른 방법이 있겠지?

오늘은 여기까지.