배열, 객체의 call by value, call by reference에 대해 공부하다가 깊은 복사를 단순하게라도 구현해보고 싶은 마음이 생겼다.
1. 객체 깊은 복사 코드
function objectDeep(origin){
const target = {};
Object.keys(origin).forEach((k)=>{
if(Array.isArray(origin[k])){
target[k] = arrayDeep(origin[k]);
}else if(typeof origin[k] === 'object'){
target[k] = objectDeep(origin[k]);
}else{
target[k] = origin[k];
}
});
return target;
}
2. 배열 깊은 복사 코드
function arrayDeep(origin){
const target = [];
origin.forEach((v)=>{
if(Array.isArray(v)){
target.push(arrayDeep(v));
}else if(typeof v === 'object'){
target.push(objectDeep(v));
}else{
target.push(v);
}
});
return target;
}
두 함수는 각각 객체 깊은 복사함수(1번), 배열 깊은 복사함수(2번)이다.
두 함수의 생김새나 하는 역할은 매우 유사한 것을 확인할 수 있다.
objectDeep을 위주로 설명해보자면
1. 재귀함수 개념을 사용하였다.
2. 해당 키 또는 인덱스에 있는 값이 배열이면 arrayDeep을 호출한다.
3. 해당 키 또는 인덱스에 있는 값이 객체이면 objectDeep을 호출한다.
4. 2번, 3번에 해당하지 않으면 원시값으로 판단하고 그대로 대입하여 복사한다.
↓ 3번은 객체안의 객체값이 해당한다고 생각하면 된다.
const obj = {
inner: {
text: '객체안의 객체',
},
}
원시값이면 복사할 배열(target)에 바로 값을 대입하지만 객체이거나 배열이라면 그대로 값을 대입해버리면 참조값만 대입되어 얉은 복사가 되므로 주의해야 한다.
3. 테스트
더미데이터
const array = [1,2,3,4,5,[6,7,8,[9,10,11]],12,13,14, {a:1,b:2}];
const target = arrayDeep(array); //array의 데이터를 깊은 복사한 배열
테스트 케이스
array.push(15);
target[9].a=55;
target[5][0] = 77777;
target[5][3][0] = 99999;
결과
테스트1. 원본 데이터 변경
array.push(15)
원본인 array의 끝에 15라는 값을 추가했지만 복사본인 target에는 추가되지 않은 것을 확인할 수 있다.
테스트2. 복사본 데이터 변경
target[9].a=55;
복사본(target)의 9번 인덱스에 위치한 객체의 a를 55로 바꾸었지만 원본(array)의 9번 인덱스에 위치한 객체는 변경되지 않은 것을 확인할 수 있다.
테스트3. 복사본 데이터 변경2
target[5][0] = 77777;
설명이 필요없다. 테스트2번의 경우와 똑같다.
아래도 마찬가지
target[5][3][0] = 99999;
이렇게 원본 또는 복사본에 있는 원시값이 아닌 객체들을 변경해도 서로 메모리가 공유되어 있지 않으니 각각 적용이 되는 것을 볼 수 있었다.
'코딩이야기 > JS' 카테고리의 다른 글
[canvas] 캔버스로 모자이크 하기 (0) | 2022.11.01 |
---|---|
[canvas] 로컬 이미지 파일 선택해서 캔버스에 가져오기 (with FileReader) (0) | 2022.10.25 |
JavaScript 배열 랜덤 섞기 (0) | 2022.10.17 |