자바스크립트 입문_얕은복사와 깊은복사

자바스크립트 2021. 5. 3. 15:13

(본 포스팅은 위키북스의 '코어자바스크립트' 책을 공부하면서 작성되었습니다_내돈내산)

 

  • 얕은복사(shallow copy) : 바로 아래단계의 값만 복사하는 방법. 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 그 주솟값만 복사한다는 의미. 해당 프로퍼티에 대해 원본과 사본이 모두 동일한 참조형 데이터의 주소를 가리키게 됨. 
  • 깊은복사(deep copy) :  내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법

<중첩된 객체에 대한 얕은 복사>

var copyObject = function(target) {
  var result = {};
  for (var prop in target){
    result[prop] = target[prop];
  }
  return result;
};

var user = {
  name : 'Jimin',
  urls: {
    portfolio : 'http://github.com/abc',
    blog : 'http://blog.com',
    facebook : 'http://facebook.com/abc',
  }
};

var user2 = copyObject(user);

user2.name = 'Yu' ;
console.log(user.name === user2.name); //false 

user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio); // true

user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog); // true

위에서 보면 첫번째 값이 false가 나오는것으로 보아 user2의 name 프로퍼티를 변경해도 user의 name 프로퍼티가 변경되지 않지만, 아래에서는 원본과 사본의 프로퍼티가 함께 변경되는것을 알 수 있음. (얕은복사를 진행한 경우 변경된 값만 주소값이 변경되었음)

 

 >> user의 바로 아랫단계의 값은 변경되엇지만, 한단계 더 들어간 url의 내부 프로퍼티들은 기존 데이터를 그대로 참조하고 있음. 이러한 현상을 방지하기 위해 user.url 프로퍼티도 불변객체로 만들 필요가 있음.

 

<중첩된 객체에 대한 깊은 복사>

var copyObject = function(target) {
  var result = {};
  for (var prop in target){
    result[prop] = target[prop];
  }
  return result;
};

var user = {
  name : 'Jimin',
  urls: {
    portfolio : 'http://github.com/abc',
    blog : 'http://blog.com',
    facebook : 'http://facebook.com/abc',
  }
};

var user2 = copyObject(user);
user2.urls = copyObject(user.urls);

user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio); // false

user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog) ; // false

!! 어떤 객체를 복사할 때 객체 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들고자 할 때, 객체의 프로퍼티 중에서 그 값이 기본형 데이터일 경우에는 그대로 복사하면 되지만, 참조형 데이터일경우는 그 내부의 프로퍼티까지 재귀적으로 복사를 수행해야만 깊은 복사가 이뤄지게 됨.

 

<객체의 깊은 복사를 수행하는 범용 함수>

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

<JSON을 활용한 간단한 깊은 복사>

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

var obj = {
  a: 1,
  b: {
    c: null,
    d: [1,2],
    func1 : function() {console.log(3);},
  },
  func2 : function() {console.log(4);},
};

var obj2 = copyObjectViaJSON(obj);

obj2.a = 3;
obj2.b.c = 4;
obj.b.d[1] = 3;

console.log(obj); // { a:1, b:{c:null, d:[1,3], func1:f(), func2:f()}}
console.log(obj2); // { a:3, b: {c:4, d: [1,2]}}

위의 방법은 객체를 JSON 문법으로 표현된 문자열로 전환햇다가 다시 JSON 객체로 바꾸는것.(전체가 다시 선언되는것과 동일한 효과를 가짐) 다만 함수나 getter/setter와 같이 JSON으로 변경할 수 없는 프로퍼티들은 모두 무시하게 됨. 

admin