얕은복사, 깊은 복사

Steve·2021년 4월 12일
0
post-custom-banner

객체는 기본적으로 참조형(reference type)임을 알고 있어야 한다.

얕은 복사

: 주소값만 복사하는 것.
ex) const updatedRemoteStreams = [...prevStreams];

  1. 리액트 불변성 :
    현재 상태를 직접 수정 x
    변경 사항이 반영된 새로운 복사본을 만듬.
    리액트는 현재 상태와 이전 상태를 비교하여 언제 컴포넌트를 리렌더링할지 판단.

  2. 직접적인 변이 방지
    [...preStreams] 사용하여 새로운 배열을 생성함으로써, updatedRemoteStreams에 대한 수정 또는 작업이 원래의 preStreams 배열에 직접 영향을 미치지 않도록해야함. 이를 따르지 않으면 예측 불가한 버그 유발.

  3. 얕은 복사
    배열자체가 새로운 객체지만 배열 안의 요소는 여전히 메모리에서 같은 객체를 참조.

예시코드)

var copyObject = function(target) {
  var result = {};
  for (var prop in target) {
    result[prop] = target[prop];
  }
  return result;
}
  • 이경우 주소값만 복사하기 때문에 만약 가리키고 있는 값 하나가 바뀌면 나머지 하나도 같이 바뀐다. ( 원본과 사본이 모두 동일한 참조형 데이터의 주소를 가리키게 된다. )
    -> 사본을 바꾸면 원본도 같이 바뀌고, 원본을 바꾸면 사본도 같이 바뀐다는 뜻.
const user = {
  name : 'goo',
  urls : {
    portfolio : 'https://github.com/seonggookang',
    blog : 'https://blog.naver.com/ksung91889'
  };
};

const user2 = copyObject(user);

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

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

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

(1)번줄의 사본인 user2의 name 프로퍼티를 바꿔도 원본 user의 name프로퍼티는 바뀌지 않았다.
user 객체에 직접 속한 프로퍼티(name)에 대해서는 복사해서 완전히 새로운 데이터를 갖고 있고,
한 단계 더 들어간 urls의 내부 프로퍼티들은 기존 데이터를 그대로 참조한다.
그렇기 때문에 원본과 사본이 계속 같아지는 현상이 나타나는데

  • 이를 방지하기 위해 user.urls 프로퍼티에 대해서도 불변 객체로 만들어야 한다. 이 때 깊은 복사의 개념이 필요하다.

깊은 복사

: 값까지 복사하는 것.

  • 값까지 모두 복사했기 때문에 한쪽이 값을 바꾼다고해도 다른쪽의 값이 바뀌지 않는다.
//객체의 깊은 복사를 수행하는 범용 함수
const copyObjectDeep =(target)=>{
  const result = {};
  if(typeof target === 'object' && target !== null){ // (1)
    for(let prop in target){
      result[prop] = copyObjectDeep(target[prop])
    }
  } else {
  result = target // (2)
 }
  return result
};

// (1)에서 target !== null 조건을 덧붙인 이유는 typeof 명령어가 null에 대해서도 'object'를 반환하기 때문이다. (자바스크립트 자체 버그이다.)

(1)에서 target이 객체인 경우 내부 프로퍼티들을 순회하며 copyObjectDeep함수를 재귀적으로 호출하고,
객체가 아닌 경우에는 (2)에서 처럼 target을 그대로 지정하게끔 했다.

이 함수를 사용해 객체를 복사한 다음에는 원본과 사본이 서로 완전히 다른 객체를 참조하게 되어 어느 쪽의 프로퍼티를 변경하더라도 다른 쪽에 영향을 주지 않는다.

tip. 간단하게 깊은 복사를 처리할 수 있는 방법

  • JSON 문법으로 표현된 문자열로 전환했다가 다시 JSON 객체로 바꾼다.
const copyObjVioJSON = (target)=>{
  return JSON.parse(JSON.stringify(target)) 
}
const obj ={
	a:1,
  	b:{
   	  c: null,
  	  d:[1,2],
     	  func1:function(){ console.log(3); }      
    },
  	func2:function(){ console.log(4); }
}

const obj2 = copyObjVioJSON(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], func1:f()},func2:f()}
profile
Front-Dev
post-custom-banner

0개의 댓글