지난 시간에는 변수에 객체가 저장된 주소를 할당하는 참조에 대해 알아보았다. 이 경우 여러 변수가 같은 객체를 가리키므로 어느 한 변수에서 객체를 수정하면 이를 참조하는 다른 변수에도 영향을 미친다.
let a = {'id': 1};
let b = a; // 참조 복사
console.log(a === b); // true
a.id = 2;
console.log(b.id); // 2
이번 시간에는 객체의 주소를 복사하는 것이 아닌 새로운 객체를 만드는 두가지 복사 방법에 대해 알아보도록 한다.
얕은 복사(Shallow copy)
얕은 복사를 하면 참조 복사와 달리 원본 객체와 다른 주소에 할당된 객체를 가리키게 된다. 다만 객체 내부의 속성들은 원본 객체와 같은 속성을 참조한다.
let original = {list: [1, 2, 3], obj: {'id': 1}}
let shallowCopy = {...original}
console.log(original === shallowCopy) // false (다른 객체 참조)
console.log(original.list === shallowCopy.list) // true (속성은 같은 객체 참조)
console.log(original.obj === shallowCopy.obj) // true (속성은 같은 객체 참조)
객체의 얕은 복사는 복사본의 속성이 복사본이 만들어진 원본 객체와 같은 참조 (메모리 내의 같은 값을 가리킴)를 공유하는 복사입니다. 따라서 원본이나 복사본을 변경하면, 다른 객체 또한 변경될 수 있습니다. 이러한 동작은 원본과 복사본이 완전히 독립적인 깊은 복사의 동작과 대조적입니다.
출처: https://developer.mozilla.org/ko/docs/Glossary/Shallow_copy
JavaScript에서, 모든 표준 내장 객체의 복사 작업은 깊은 복사가 아닌 얕은 복사본을 생성한다.
- 전개 구문
- Array.prototype.concat()
- Array.prototype.slice()
- Array.from()
- Object.assign()
- Object.create()
라이브러리를 사용해서 얕은 복사를 하는 방법도 있다.
const _ = require('lodash');
let originalArray = [1, 2, 3];
let shallowCopyArray = _.clone(originalArray);
깊은 복사(Deep copy)
어떤 객체에 대해 원본과는 독립적인 복제본을 생성하고자 한다면 깊은 복사를 해야한다.
깊은 복사는 원본 객체와 참조를 공유하지 않기 때문에 깊은 복사본에 어떠한 변경이 있어도 원본 객체에 영향을 주지 않는다.
객체의 깊은 복사는 복사본의 속성이 복사본이 만들어진 원본 객체와 같은 참조(메모리 내의 같은 값을 가리킴)를 공유하지 않는 복사입니다. 따라서 원본이나 복사본을 변경할 때, 다른 객체가 변경되지 않는 것을 보장할 수 있습니다. 이러한 동작은 원본이나 복사본의 중첩된 속성을 변경하면 다른 객체도 변경될 수 있는 얕은 복사의 동작과 대조적입니다.
출처: https://developer.mozilla.org/ko/docs/Glossary/Deep_copy
재귀함수를 이용한 깊은 복사
객체 또는 배열의 각 요소를 순회하면서 각 요소를 복사하여 새로운 객체 또는 배열을 생성하는 재귀 함수를 작성할 수 있다.
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let newObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepCopy(obj[key]);
}
}
return newObj;
}
JSON.stringify()와 JSON.parse()를 이용한 깊은 복사
JSON.stringify()를 사용하여 객체를 JSON 문자열로 변환한 다음, JSON.parse()로 문자열을 다시 (완전히 새로운) JavaScript 객체로 변환하는 것이다.
const myList = ['hello', 'world', {}]
const myListDeepCopy = JSON.parse(JSON.stringify(myList))
다만, 원본 객체의 프로퍼티 중 함수와 같이 JSON으로 변환할 수 없는 데이터가 있는 경우에는 제대로 작동하지 않는다.
라이브러리를 이용한 깊은 복사
lodash 라이브러리의 _.cloneDeep() 함수를 사용할 수 있다.
const _ = require('lodash');
let originalObject = { /* 원본 객체 */ };
let deepCopyObject = _.cloneDeep(originalObject);
참고자료
'언어 > Javascript & Typescript' 카테고리의 다른 글
[JS] 복제, 참조 그리고 함수의 매개변수 (0) | 2024.05.01 |
---|---|
[JS] 자바스크립트의 데이터 타입 (0) | 2024.05.01 |
[JS] 자바스크립트 표준입력, 정규표현식, 2차원 배열 (0) | 2023.07.10 |