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

JKim·2023년 3월 2일
post-thumbnail

얕은 복사, 깊은 복사는 참조 자료형에서 발생한다.
참조 자료형부터 간단하게 짚고 넘어가보자.

참조 자료형

  • 메모리 공간에 값이 아닌 주소를 할당하여, 할당된 주소 안의 값을 호출 및 수정한다.

  • 참조 자료형의 값을 다른 변수에 할당하면 주소 자체가 할당되어, 새로운 변수에서 값을 변경하면 원본 값도 함께 변경된다.

  • 할당된 주소의 위치는 heap이라는 공간에 존재한다.

  • 종류 : array, object, function

참조 자료형의 복사 방법

배열

1. slice()

  • slice()는 배열의 원본 값에서 특정 범위를 제한하여 새로운 배열을 반환하는 메소드
  • 새로운 배열을 반환하기 때문에, 메모리 공간에도 새롭게 할당되며, 원본과 연결되지 않는다.

2. spread syntax(스프레드 문법)

let arr = [0, 1, 2, 3];

console.log(...arr);
// 0, 1, 2, 3 => 배열의 형태가 아닌 내부 요소들을 각각 출력

let copiedArr = [...arr];
// spread 문법으로 내부 요소들을 [] 안에 넣음으로써
// 원본의 값을 가진 새로운 배열 생성

copiedArr.push(4);
console.log(arr) // [0, 1, 2, 3]
console.log(copiedArr) // [0, 1, 2, 3, 4]
  • 배열의 내부 요소 값들을 펼쳐서 출력해주는 문법

객체

1. Object.assign()

  • 객체를 복사하는 메소드
  • let newObj = Object.assign(복사할 객체1, 복사할 객체2)
    ⇒ 복사할 객체1은 {}로 빈 객체 할당이 가능하다.
  • 복사할 객체들의 중복된 요소들은 순서대로 다음 객체의 값으로 덮어진다.

2. spread syntax(스프레드 문법)

  • 배열과 사용 방식 동일

얕은 복사

중첩된 구조들 중 한 단계까지만 복사를 하는 것을 얕은 복사라고 한다.

  • 참조 자료형 안에 참조 자료형 요소가 있을때, 내부 참조 자료형의 주소값은 변경이 되지 않는다.
  • 외부적으로는 새로운 주소를 할당하였으나, 그 안의 요소값들의 주소가 원본에서 변경되지 않는다.
let arr = [
	{
		name: "kimcoding",
		age: 26,
		job: "student"
	},
	{
		name: "parkhacker",
		age: 29,
		job: "web designer"
	},
];

let newArr = arr.slice();

console.log(arr === newArr) // false
console.log(arr[0] === newArr[0]) // true

깊은 복사

내부 요소들을 모두 새롭게 복사하는 행위를 깊은 복사라고 한다.

  • JS는 내부적으로 깊은 복사를 하는 기능이 없다.
  • JSON.parse와 JSON.stringify를 통해 참조 자료형 ⇒ 문자열 ⇒ 참조 자료형 의 구조로 완전히 새로운 참조 자료형을 만드는 방법을 이용한다.

  • console.log(copiedArr.oneReturn) 의 출력 결과를 보면 undefined가 출력되고 있다.
  • stringify는 함수, undefined, Symbol의 자료형 요소들은 처리 하지 못한다.(무시해버린다)

깊은 복사를 지원하는 외부 라이브러리

ramda, lodash는 deep copy를 쉽고 간편하게 사용할 수 있게 지원해준다.(관련 블로깅은 차후에 작성)

const lodash = require("lodash");
const ramda = require("ramda");

const arr = [1, 2, [3, 4]];
const lodashArr = lodash.cloneDeep(arr);
const ramdaArr = ramda.clone(arr);

console.log(lodashArr); // [1, 2, [3, 4]]
console.log(arr[2] === lodashArr[2]); // false
console.log(ramdaArr); // [1, 2, [3, 4]]
console.log(arr[2] === ramdaArr[2]); // false
profile
프론트엔드 개발자 | 문제가 있는 내용이 있다면 댓글로 알려주세요.

0개의 댓글