배열, 객체의 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;

이렇게 원본 또는 복사본에 있는 원시값이 아닌 객체들을 변경해도 서로 메모리가 공유되어 있지 않으니 각각 적용이 되는 것을 볼 수 있었다.

+ Recent posts