JavaScript: 얕은 복사와 깊은 복사

MARCOIN·2022년 5월 18일

0. 참조형 객체의 복사 문제

var user = {
    name: 'James',
    urls: {
        portfolio: 'https://blog.naver.com/james',
        blog: 'https://blog.net/jamesblog',
        facebook: 'https://www.facebook.com/jameslee'
    }
};

var user2 = user;

user.name = 'Jessica';

console.log(`user name: ${user.name}`) //user name: Jessica
console.log(`user name2: ${user2.name}`) //user name2: Jessica

앞선 학습에서 언급했듯 참조형 객체를 복사하여 만든 경우 복사 객체의 경우 원본 객체의 참조하는 주소를 대입했기 때문에 원본 혹은 복사 객체의 값을 변경하면 함께 변경되는 이슈가 있다. 이러한 문제로 예측이 불가능한 오류를 발생시킬 수 있다.


1. 얕은 복사 (Shallow Copy)

  • 얕은 복사 (Shallow Copy)는 바로 아래 단계의 값만 복사
  • 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 주솟값만 복사
  • 원본과 사본이 모두 동일한 참조형 데이터의 주소를 가르키게 되며 사본을 바꾸면 원본도 바뀌고, 원본을 바꾸면 사본도 바뀜
var user = {
    name: 'James',
    urls: {
        portfolio: 'https://blog.naver.com/james',
        blog: 'https://blog.net/jamesblog',
        facebook: 'https://www.facebook.com/jameslee'
    }
};

var user2 = user;

console.log(`user name: ${user.name}`); //user name: James
console.log(`user2 name: ${user2.name}`); //user2 name: James
console.log(user.name == user2.name) //true

user2.name = 'Jessica'; 
console.log(`user name: ${user.name}`); //user name: James
console.log(`user2 name: ${user2.name}`); //user2 name: Jessica
console.log(user.name == user2.name) //false

console.log(`user blog: ${user.urls.blog}`); //https://blog.net/jamesblog
console.log(`user2 blog: ${user2.urls.blog}`); //https://blog.net/jamesblog
console.log(user.urls.blog == user2.urls.blog) //true

user2.urls.blog = 'https://twitter.com/jessica'
console.log(`user blog: ${user.urls.blog}`); //https://twitter.com/jessica
console.log(`user2 blog: ${user2.urls.blog}`); //https://twitter.com/jessica
console.log(user.urls.blog == user2.urls.blog) //true

3. 깊은 복사

  • 깊은 복사 (Deep Copy)는 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방식
  • 얖은 복사와는 다르게 객체 내부의 객체의 상태까지 모두 복사함
  • 객체를 깊은 복사하는 방법에는 '외부 깊은 복사 라이브러리'를 이용하는 방법, '객체 내의 함수를 탐색하여 깊은 복사를 수행하는 범용 함수'를 활용하는 방법, 'JSON'을 활용하는 방법이 있다. (외부 라이브러리를 사용하는 방법은 다루지 않겠음)

3.1. 객체의 깊은 복사를 수행하는 범용 함수

//객체 내의 함수를 탐색하여 깊은 복사를 수행하는 범용 함수

var copyObjectDeep = function(target){
    var result = [];

    if(typeof target === 'object' && target != null){
        for (var prop in target){
            result[prop] = copyObjectDeep(target[prop]);
        }
    } else{
        result = target;
    }
    return result;
};



var user = {
    name: 'James',
    urls: {
        portfolio: 'https://blog.naver.com/james',
        blog: 'https://blog.net/jamesblog',
        facebook: 'https://www.facebook.com/jameslee'
    }
};

var user2 = copyObjectDeep(user);

console.log(`user name: ${user.name}`); //user name: James
console.log(`user2 name: ${user2.name}`); //user2 name: James
console.log(user.name == user2.name) //true

user2.name = 'Jessica'; 
console.log(`user name: ${user.name}`); //user name: James
console.log(`user2 name: ${user2.name}`); //user2 name: Jessica
console.log(user.name == user2.name) //false

console.log(`user blog: ${user.urls.blog}`); //https://blog.net/jamesblog
console.log(`user2 blog: ${user2.urls.blog}`); //https://blog.net/jamesblog
console.log(user.urls.blog == user2.urls.blog) //true

user2.urls.blog = 'https://twitter.com/jessica'
console.log(`user blog: ${user.urls.blog}`); //https://blog.net/jamesblog
console.log(`user2 blog: ${user2.urls.blog}`); //https://twitter.com/jessica
console.log(user.urls.blog == user2.urls.blog) //true

3.2. JSON을 활용한 간단 깊은 복사

편한 방법이지만 위의 함수보다 느림

var copyObjectViaJSON = function (target){
    return JSON.parse(JSON.stringify(target));
};

var user = {
    name: 'James',
    urls: {
        portfolio: 'https://blog.naver.com/james',
        blog: 'https://blog.net/jamesblog',
        facebook: 'https://www.facebook.com/jameslee'
    }
};

var user2 = copyObjectViaJSON(user);

console.log(`user name: ${user.name}`); //user name: James
console.log(`user2 name: ${user2.name}`); //user2 name: James
console.log(user.name == user2.name) //true

user2.name = 'Jessica'; 
console.log(`user name: ${user.name}`); //user name: James
console.log(`user2 name: ${user2.name}`); //user2 name: Jessica
console.log(user.name == user2.name) //false

console.log(`user blog: ${user.urls.blog}`); //https://blog.net/jamesblog
console.log(`user2 blog: ${user2.urls.blog}`); //https://blog.net/jamesblog
console.log(user.urls.blog == user2.urls.blog) //true

user2.urls.blog = 'https://twitter.com/jessica'
console.log(`user blog: ${user.urls.blog}`); //https://blog.net/jamesblog
console.log(`user2 blog: ${user2.urls.blog}`); //https://twitter.com/jessica
console.log(user.urls.blog == user2.urls.blog) //true
profile
공부하는 기획자 👀

0개의 댓글