깊은 복사, 얕은 복사

date
Sep 3, 2022
thumbnail
slug
깊은 복사, 얕은 복사
author
status
Published
tags
JavaScript
summary
오늘은 자바스크립트에서의 깊은 복사와 얕은 복사를 알아보려고 해요. 단어에서도 유추할 수 있듯이 깊은 복사는 내부 값 전체를 복사, 얕은 복사는 얕게 복사하는 것이겠죠.?
type
Post
updatedAt
Jan 22, 2023 01:19 AM
오늘은 자바스크립트에서의 깊은 복사와 얕은 복사를 알아보려고 해요.
단어에서도 유추할 수 있듯이 깊은 복사는 내부 값 전체를 복사, 얕은 복사는 얕게 복사하는 것이겠죠.?

얕은 복사

let copyObject = (target) => {
	let result = [];
    for (let prop in target) {
    	result[prop] = target[prop]
    }
    return result
}
위 copyObject라는 함수는 result 객체에 target 객체의 프로퍼티를 복사하는 함수에요.
저희가 만든 함수는 간단한 만큼 아쉬운 점이 있어요.얕은 복사만 수행한다는 점인데요.
얕은 복사란 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 주소값만 복사한다는 의미입니다.
그렇게 되면 사본을 바꾸면 원본이 바뀌고 원본을 바꾸면 사본이 바뀌는 현상이 일어나죠.
예를 들어 아래와 같은 객체를 copyObject함수로 복사해봅시다.
let user = {
	name: 'jun',
  	userInfo:{
       age: '23',
       role: 'frontend'
    }
}

let newUser = copyObject(user);

newUser.name = 'hyeok';
console.log(newUser.name === user.name); //false

user.userInfo.age = '20';
console.log(newUser.userInfo.age === user.userInfo.age); //true
위 예시처럼 바로 아래 존재하는 객체는 복사하지만 userInfo 객체의 데이터는 함께 바뀌는 것을 볼 수 있는데요.
이런 현상을 막기 위해 불변객체로 만들 필요가 있습니다.

깊은 복사

직접 데이터 복사하기

let newUser = copyObject(user);

newUser.userInfo = copyObject(user.userInfo);
newUser.userInfo.age = '20';
console.log(newUser.userInfo.age === user.userInfo.age); //false
이렇게 객체를 복사할 때 내부의 모든 값을 복사해서 새로운 값을 만든다고 할 때 기본형 데이터일 경우 그대로 복사하면 되지만 참조형 데이터는 내부 프로퍼티를 다시 복사해야합니다.
이와 같은 방식으로 coptObject를 변경해봅시다.
const deepObjectCopy = (target) => {
	let result = [];
    if(typeof target === 'object' && target !== null){
      //typeof는 null에 대해도 object를 반환합니다.
		for (let prop in target){
        result[prop] = deepObjectCopy(target[prop]);
        }
    } else {
    	result = target;
    }
    return result;
 }
target이 객체일 경우 내부 프로퍼티를 순회하며 재귀적으로 호출하고 객체가 아닌 경우 target을 그대로 저장하는 함수 입니다.

JSON 이용하기

다른 방법으로 JSON을 이용할 수도 있습니다.
객체를 JSON 문법으로 표현된 문자로 변경했다가 다시 JSON으로 변경하는 방법입니다.다만 함수나 숨겨진 프로퍼티( __proto __, getter/setter)와 같은 JSON으로 변경이 불가능한 것들은 모두 무시합니다.
데이터와 같은 정보를 복사할 때 좋은 방법입니다.
let JsonCopyObject = () => {
	return JSON.parse(JSON.stringify(target));
}