비밀번호

커뮤니티2

구글태그매니저[Google Tag Manager] 구글태그매니저 커뮤니티입니다.

[JavaScript] 얕은 복사와 깊은 복사

자바스크립트에도 원본 객체와 같은 참조값을 공유하는 얕은 복사와 원본 객체와 같은 참조값을 공유하지않는 깊은 복사가 존재합니다.

먼저 자바스크립트 변수 자료형에는 원시형(Primitive value 또는 Primitive data type)

string

number

bigint

boolean

undefined

symbol

null

참조형(Reference value 또는 Reference data type)이 존재합니다.

array

object

function

data

얕은 복사는 복사한 변수들끼리 서로를 참조하고 있기 때문에, 하나의 값을 변경하면 전부 다 같이 변경됩니다.

깊은 복사는 복사한 변수들끼리 서로를 참조하지 않기 때문에, 하나의 값을 변경해도 그 변수만 값이 변경됩니다.

참조형 변수를 복사할 때 무심코 얕은 복사를 한 후, 변수 안의 값을 변경하면,
원본 변수 포함 모든 참조형변수의 값이 변경되는 원치 않는 상황이 발생할 수도 있습니다.

필요한 상황에 맞춰 복사 방법을 사용하여 원치않는 상황을 피할 수 있도록 합니다.

제일 중요한 건 복사 하고자 하는 값이 참조형이냐 아니냐에 따라 얕은 복사, 깊은 복사가 결정됩니다.

let a1 = [0, 1, 2];
let a2 = a1;
let a3 = [...a1];

위와 같은 경우 a2는 얕은 복사가 되어 a2의 원소값을 변경하면 a1도 변경됩니다.
하지만 a3는 전개 연산자(...)를 통해 원시 자료형의 숫자(Number)들이 전개되어 복사 했기 때문에 깊은 복사가 이루어져, a3의 원소값을 변경해도 a1은 변하지 않습니다.


let a1 = [[0], [1], [2]];
let a2 = a1;
let a3 = [...a1];

위와 같은 경우 a2는 얕은 복사가 되어 a2의 원소값을 변경하면 a1도 변경됩니다.
a3는 전개 연산자(...)를 통해 참조 자료형인 배열(Array)들이 전개되어 복사 했기 때문에 얕은 복사가 이루어져, a3의 원소값을 변경하면 a1도 변합니다.

객체 복사 함수들(concat, slice, assign 등)을 사용하여도 얕은 복사가 이루어집니다.


얕은 복사를 피해 무조건 깊은 복사를 하는 방법을 알아봅시다.

1. 함수 만들기

위에서 얕은 복사와 깊은 복사의 차이를 알게 되었습니다.
typeof 를 이용하여 배열 또는 객체 변수를 인자로 받았을 때, 각 원소 값들의 자료형을 typeof로 확인하여 참조형인 경우에는 안쪽에 원시값이 나올때까지 접근하여 복사하는 방식의 함수를 만들어 사용할 수 있습니다.
이 방법은 비추천합니다.

2. 외부 라이브러리 사용하기

lodash, fast-copy 등 여러가지 깊은 복사 라이브러리를 사용하는 방식입니다.
외부 라이브러리를 사용할 수 있는 환경이시라면 이 방법을 추천합니다.

3. JSON.parse(JSON.stringify())

참조형 변수의 값을 통째로 문자열로 변경한 후 다시 파싱을 통하여 참조형 변수로 만들기 때문에 깊은 복사가 됩니다.
변수의 원소값들이 단순히 원시자료형이라면 문제가 없지만, 만일 원소 값이 참조형 중 function, data 같은 특수한 경우라면 해당 방법을 사용했을 때 오류가 발생할 수 있습니다.
간단한 변수를 복사하는데 사용한다면 추천하지만, 일반적으로 추천하지 않는 방법입니다.

4. structuredClone()

원본 변수를 인자로 넣고 반환값으로 복사할 변수에 대입하면 되는 기본 제공 함수입니다.
라이브러를 따로 설치하지 않아도 되고, 3번 방식의 단점도 해결되는 아주 좋은 깊은 복사 방법입니다.
브라우저의 버전(22년 이후 버전)만 맞는다면 해당 기능을 가장 추천합니다.(참조 url)

자바스크립트의 변수 자료형(원시형, 참조형)과 해당 변수들을 복사했을 때 발생하는 얕은 복사와 깊은 복사에 대해 정리가 잘 된다면 변수 관리할 때 불편함이 없을 것 입니다.

전체댓글0

1