문제 원인
코드 작성 중 원본 배열을 저장해 두고 새로운 배열을 만들 일이 생겼었는데 객체의 같은 메모리의 주소값을 참조하여 복사한 데이터를 수정하면 원본 데이터도 같이 수정되는 일이 있었다.
문제 코드
const originalData = [
{
name:"김아무개",
age:10
},
{
name:"이아무개",
age:14
},
{
name:"박아무개",
age:18
}
]
let cloneData = originalData;
cloneData[0].age = 12;
console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)
문제 코드의 실행 결과는

이 것과 같이 cloneData의 나이를 변경 하였지만 originalData에도 반영이 된 것 을 볼 수 있다.
해결 방안
예상 원인으로 객체가 메모리의 같은 주소를 참조해서 그런거 같다 라고 생각을 했었는데 그 예상이 맞았고 찾아보니 이와 관련해서 깊은 복사 얕은 복사라는 용어가 있었다.
깊은 복사(deep copy)
주소 값이 아닌 다른 주소를 참조하여 복사하는 것 을 의미한다.
깊은 복사는 재귀 함수, JSON 객체, structuredClone(), Lodash가 있다.
structuredClone()
const originalData = [
{
name:"김아무개",
age:10
},
{
name:"이아무개",
age:14
},
{
name:"박아무개",
age:18
}
]
let cloneData = structuredClone(originalData);
cloneData[0].age = 12;
console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)
JSON 객체
const originalData = [
{
name:"김아무개",
age:10
},
{
name:"이아무개",
age:14
},
{
name:"박아무개",
age:18
}
]
let cloneData = JSON.parse(JSON.stringify(originalData));
cloneData[0].age = 12;
console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)
재귀 함수
const originalData = [
{
name: "김아무개",
age: 10
},
{
name: "이아무개",
age: 14
},
{
name: "박아무개",
age: 18
}
]
function deepCopy(object) {
if (object === null || typeof object !== "object") {
return object;
}
// 객체인지 배열인지 판단
const clone = Array.isArray(object) ? [] : {};
for (let idx of Object.keys(object)) {
clone[idx] = deepCopy(object[idx]);
}
return clone;
}
let cloneData = deepCopy(originalData);
cloneData[0].age = 12;
console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)
Lodash
import lodash from "lodash"
const originalData = [
{
name: "김아무개",
age: 10
},
{
name: "이아무개",
age: 14
},
{
name: "박아무개",
age: 18
}
]
let cloneData = lodash.cloneDeep(originalData);
cloneData[0].age = 12;
console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)

위 예제와 같이 김아무개의 이름이 바뀌지 않는다는 것 을 알 수 있다.
얕은 복사(Shallow copy)
새로운 메모리에 할당 하는 것이 아닌 메모리 주소값을 복사하여 같은 메모리를 참조하는 것을 의미한다.
=로 복사하는 것이 여기에 속합니다.
splice(), 전개연산자, assign()은 = 과는 약간 다른 양상을 보이는데
orginalData === cloneData를 했을 때 =은 true가 나왔던 반면에 splice()는 false가 나왔다.
1차원 배열은 깊은 복사가 되는 반면 1차원 배열 안에 들어있는 2차원 배열의 경우 얕은 복사가 된다.
splice()
const originalData = [
{
name:"김아무개",
age:10
},
{
name:"이아무개",
age:14
},
{
name:"박아무개",
age:18
}
]
let cloneData = originalData.slice();
cloneData[0].age = 12;
console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)
전개 연산자
const originalData = [
{
name:"김아무개",
age:10
},
{
name:"이아무개",
age:14
},
{
name:"박아무개",
age:18
}
]
let cloneData = [...originalData];
cloneData[0].age = 12;
console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)

'JavaScript' 카테고리의 다른 글
자바스크립트 상속 (0) | 2024.01.09 |
---|