[Javascript] 깊은 복사와 얕은 복사가 뭘까?

yo_onms·2022년 1월 26일
0

Javascript

목록 보기
1/2
post-thumbnail

최근 React로 개발을 하던 중 하나의 객체를 2개로 복사 후 각각 데이터를 쌓아야 하는 일이 있었다. 이때 복사한 객체들이 같이 변화 된다는 사실을 알게 되었다. 이에 의문을 가진 나는 복사에 대해 알아보기로 하였다.

☝ 우선 의문을 가지게 된 코드예시를 보자

import React from "react";

var dummyData = {
 name: "React",
 urls:{
   portfolio: "http://github.com",
   blog: "http://velog.io",
   facebook : "http://facebook.com"
 }
};

var user1 = dummyData;
var user2 = dummyData;

export default function App() {

  console.log("user1",user1);
  console.log("user2",user2);

  return <div className="App"></div>;
}

-console-

user1

name: "React",
urls:{
  portfolio: "http://github.com"
  blog: "http://velog.io"
  facebook: "http://facebook.com"
}

user2

name: "React",
urls:{
  portfolio: "http://github.com"
  blog: "http://velog.io"
  facebook: "http://facebook.com"
}

이런식으로 하나의 데이터를 2개의 변수에 각각 저장을 해보았다.

여기서 user2의 urls.portfolio 값을 변화 시켰더니 user1의 값도 같이 변하는 현상을 발견 했다.

🤔 코드로 보자

import React from "react";

var dummyData = {
 name: "React",
 urls:{
   portfolio: "http://github.com",
   blog: "http://velog.io",
   facebook : "http://facebook.com"
 }
};

var user1 = dummyData;
var user2 = dummyData;

export default function App() {

  user2.urls.portfolio = "http://tistory.com"
  
  console.log("user1",user1.urls.portfolio);
  console.log("user2",user2.urls.portfolio);

  return <div className="App"></div>;
}

-console-

user1 http://tistory.com 
user2 http://tistory.com 

나는 분명 객체를 복사하여 각각 다른 객체에 넣었는데 왜 같이 값을 변화 할까? 라는 의문점을 가지게 되었고 자바스크립크 책을 통해 알게되었다.

예제를 한번 보자

기본형 데이터일 경우

a=0; === 이름 : a, 데이터 = 0, 주소값 = 50001;
a=1; === 이름 : a, 데이터 = 1, 주소값 = 5002;

이런식으로 a란 변수를 바꾸게 되면 매번 새로운 객체를 만들어 데이터 영역에 저장을 하고 해당 주소를 a에 저장을 하게 된다 이렇게 되면 우리가 보는 시선을 a는 값이 바뀌어 보이는 것이고 이것이 불변값의 성질이다.

만약 참조형 데이터(중첩 객체)일 경우 얕은 복사를 하게 되면 주소값을 복사하게 되는데 위의 기본형 데이터와 달리 새로운 객체가 만들어 지는 것이 아닌 기존의 객체 내부의 값만 바뀌게 되는것이다.

🤔그럼 이걸 어떻게 해야 깊은복사가 되게 할수 있는것일까?

예시코드를 보자

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

3번째 줄에서 target이 객체인 경우에는 내부 프로퍼티들을 순회하며 copyObjectDeep 함수를 재귀적으로 호출하고, 객체가 아닌 경우 8번째 줄에서 target을 그대로 지정하게끔 했습니다. 이 함수를 사용해 객체를 복사한 다음에는 원본과 사본이 서로 완전히 다른 객체를 참조하게 되어 어느 쪽의 프로퍼티를 변경하더라도 다른 쪽에 영향을 주지 않습니다.

내가 보기에는 너무나 복잡하였다.

그래서 조금더 구글링을 통해 좀더 쉽게 깊은 복사를 하는 방법을 찾아보았다.

🤭 그 결과

JSON.parse(JSON.stringify(data))

객체를 JSON문법으로 표현된 문자열로 전환했다가 다시 JSON객체로 바꾸는 방법이 있었다. 이 방법은 간단하면서도 잘 동작했다. 다만 문제점이 있다만 메서드나 숨겨진 프로퍼티인 __proto나 getter/setter 등과 같이 JSON으로 변경할수 없는 프로퍼티들을 모두 무시하였다.
대신 순수한 정보만 다룰때는 활용하기 아주 유용했다.

그 결과

import React from "react";

var dummyData = {
 name: "React",
 urls:{
   portfolio: "http://github.com",
   blog: "http://velog.io",
   facebook : "http://facebook.com"
 }
};

var user1 = dummyData;
var user2 = JSON.parse(JSON.stringify(dummyData));

export default function App() {

  user2.urls.portfolio = "http://tistory.com"
  
  console.log("user1",user1.urls.portfolio);
  console.log("user2",user2.urls.portfolio);


  return <div className="App"></div>;
}
-console-
  
user1 http://github.com 
user2 http://tistory.com 

이처럼 객체들이 각각 다르게 변경되는것을 확인 할수 있었다.

자바스크립트의 가장 중요하면서도 기초적인 개념을 다시 한번 배웠던 기회가 되었던거 같다. 아직 많이 부족하다는 것을 느꼇고 오늘도 한 발자국 나아간거 같아 기분이 좋았다.

이상 얕은 복사와 깊은 복사를 알아가는 시간 이었습니다.
감사합니다🙏

profile
프론트엔드 주니어 개발자

0개의 댓글