JS에 대해서 하나씩 알아가고 있다.
다른 언어에 대해서 배웠던 기본적인 내용들도 리마인드 시키면서 공부하는 중인데, 객체에 대한 메소드를 확인하고 있었다.
그 중에 assign의 역할이 객체를 복사해서 새로운 객체에 할당할 때 사용한다라고 확인했다.
이 순간 '아 이건 깊은 복사(deep copy)인가?'라는 생각이 들었다.
예전에 분명 deep copy와 shallow copy의 차이점을 배웠는데...
시간이 지나고 개념에 대한 정리를 하지 않으니 머릿속에 껍데기만 남은 것 같았다!
그래서 각 개념들에 대해서 한 번 되짚어보고자 한다.
일단 Copy의 개념은 모두 참조형 데이터를 기반으로 작성했다.
기본형 데이터의 경우 JS는 변수의 값이 같으면 같은 데이터 영역의 주소를 바라보게 하기 때문에 Copy시 변수 값을 복사해올 수 있다.
이 부분을 찾아보고 확인할 때 가장 많이 헷갈렸다.
var obj = {
a : 1,
b : "Jane",
c : {
x : 1,
y : "Key"
}
};
var obj1 = {...obj}; //spread operator 활용
console.log(obj === obj1); // false
console.log(obj.a === obj1.a); // true
console.log(obj.c === obj.c); // true
해당 obj 객체를 spread operator를 통해 obj1으로 얕은 복사를 진행했다.
현재 각 개체의 해당하는 값들을 변경하지 않았기 때문에 비교했을 때 같다고 확인할 수 있었지만
obj1.a = 10;
console.log(obj.a === obj1.a); // false
console.log(obj.a); // 1
console.log(obj1.a); // 10
obj1의 a에 해당하는 값을 바꾸면 서로 다른 값을 가진다는 것을 확인할 수 있다.
덕분에 주소 값을 복사하는 것이 아닌 변수의 값을 복사해올 수 있었다.
하지만 중첩객체, 즉 객체 안에 존재하는 객체에 대해서는 변수의 값을 복사할 수 없다.
obj1.c.x = 10;
console.log(obj.c === obj.c); // true
console.log(obj.c.x); // 10
console.log(obj1.c.x); // 10
사실 중첩 객체에 대해서 '주소 값을 복사해왔다'기 보다는 obj.c의 해당하는 변수 값 자체가 객체 c의 데이터를 담는 곳을 가르키는 주소 값이기에 객체의 한 단계 아래 부분 값만 복사하는 얕은 복사로는 어려울 것이다.
객체 안의 존재하는 값들을 복사해올 때 모든 참조를 없애는 것이다.
쉽게 말해서 값만 복사해오고, 주소는 다르게 설정하는 것이다.
값만 복사해오고 싶은 건 얕은 복사와 같으나, 주소를 다르게 하는 것이 목적이다.
대표적으로 두 가지 방법이 있다.
첫째, 재귀함수(recursive function)
var copyObjectDeep = function(target) {
var result = {};
if (typeof target === 'object' && target !== null) {
for (var prop in target) {
result[prop] = copyObjectDeep(target[prop]);
}
} else {
result = target;
}
return result;
}
객체의 typeof 값이 object라는 걸 이용해 중첩 객체에 대해서도 변수 값을 복사할 수 있다.
var obj2 = copyObjectDeep(obj);
obj2.a = 3;
obj2.c.x = 4;
console.log(obj); // { a: 1, b: 'Jane', c: { x: 1, y: 'Key' } }
console.log(obj2); // { a: 3, b: 'Jane', c: { x: 4, y: 'Key' } }
console.log(obj === obj2); // false
실제 실행한 결과 obj와 obj2의 중첩 객체의 값이 달라진걸 확인할 수 있다.
둘째, JSON.parse(JSON.stringify()) 활용
var obj3 = JSON.parse(JSON.stringify(obj));
JS 값(문자나 객체)을 JSON 문자열로 바꿔주는 stringify() 함수를 통해 값을 바꾸고 parse()로 구분하여 복사를 하면 주소가 서로 다른 값을 복사할 수 있다.
그러나 함수나 undefined와 같은 속성 값은 복사되지 않고, 중첩 객체 또한 복사할 수 없다.
그래서 나는 뭐가 헷갈렸던 것인가?
C++의 경우
얕은 복사 - 객체 복사 시, 주소 값 복사
깊은 복사 - 객체 복사 시, 객체의 변수 값 복사
JS의 경우
얕은 복사 - 객체 복사 시, 한 단계 아래에 있는 변수 값 복사
깊은 복사 - 객체 복사 시, 객체의 모든 변수 값을 복사
이전까지는 JS에 대해서 정리 및 활용을 하지 않아서 머리 속에서 혼란스러웠던 것 같다.
위에 내용부분 수정합니다!
https://velog.io/@changyon99/JS-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0...Copy2
그래서 결국 처음에 이런 생각을 일으킨 assign()은 뭔데?

객체에 있는 값들을 복사하는 것이다.
근데 이제 해당 값들에 대해서는 주소 값을 복사한다.
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source, {d:10});
console.log(target);
// Expected output: Object { a: 1, b: 4, c: 5 }
returnedTarget.a = 20;
console.log(returnedTarget === target); // true
console.log(returnedTarget.a); // 20
console.log(target.a); // 20
때문에 얕은 복사와 깊은 복사의 개념이 아닌 단순 객체에 대한 복사를 진행할 수 있다는 것을 알게 됐다.
(출처: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)