[Javascript] js 깊은 복사(Deep Copy), 객체 복제(Clone Object)

[Javascript] js 깊은 복사(Deep Copy), 객체 복제(Clone Object)

자바스크립트 문자열(String)과 숫자(Number)는 native 타입이어서 또 다른 변수에 대입하면 동일해진다(값 복사).

그러나 객체(Object)와 배열(Array)은 또 다른 변수에 대입하면 참조 상태(개념적으로 보면 일종의 포인터만 갖고 있는 상태)가 된다.

관련한 오류를 피하려면 얕은 복사(Shallow Copy) 대신 깊은 복사(Deep Copy)를 수행해야 한다.

객체/배열을 복사해서 새로운(기존과 독립인) 새로운 객체/배열을 만드는 것이다.

자바스크립트 깊은 복사는 eval을 쓰는 등 여러가지 방법이 있다.

1. JSON 객체를 사용한 깊은 복사 (객체/배열 복제)


JSON 객체를 사용해서 깊은 복사를 한다. 먼저 문자열로 만들고, 문자열을 다시 파싱하는 식이다.


// js 깊은 복사
function deepCopy(_obj) {
    if (_obj == null) {
        return null;
    }


    return JSON.parse(JSON.stringify(_obj));
}

2. 직접 구현한 깊은 복사 (객체/배열 복제)


아래는 JSON 객체를 사용하지 않고 직접 짠 함수다. 이 함수의 특징/사용상 주의사항은 다음과 같다.

1. 객체(Object, {}) 또는 배열(Array, [])을 깊은 복사한다.

2. 함수(Function)는 복사하지 않는다.

3. 배열과 객체의 구분은 length 요소가 있는지로 판별한다.

  (배열이 아닌데 하필 length 요소가 존재한다면 오류가 발생할 수 있다.)

4. 리턴용 객체 인스턴스를 만들 때 생성자를 활용하지 않는다.

  (생성자를 활용하려면 var newObj = new Object(); 대신 var newObj = _obj.constructor(); 식으로 코딩하면 된다.)

// js객체를 깊은 복사한다.
function deepCopy(_obj) {
    if (_obj == null || typeof(_obj) == null) {
        return null;
    }

    // 숫자 복사
    if (typeof(_obj) == “number”) {
        return parseInt(_obj + “”, 10);
    }

    // 문자열 복사
    if (typeof(_obj) == “string”) {
        return _obj + “”;
    }

    if (typeof(_obj) == “object”) {
    
        var bArray = false;
    
        try {
            // 배열 여부는 length 로만 판단한다.
            if (_obj.length === parseInt(_obj.length, 10)) {
                bArray = true;
            }
        } catch (e) {}
    
        // 배열 복사
        if (bArray) {
            var newArray = new Array();
        
            var cnt = _obj.length;
            for (var i=0; i<cnt; i++) {
                newArray[i] = deepCopy(_obj[i]);
            }
        
            return newArray;
        }
    
        // 객체 복사
        var newObj = new Object();
    
        for (var attr in _obj) {
            if (_obj.hasOwnProperty(attr)) {
                newObj[attr] = deepCopy(_obj[attr]);
            }
        }
    
        return newObj;
    }

    // 숫자, 문자열, 배열 외에는 복사하지 않는다. (ex: function)
    return null;
}