StructuredClone

sooni·2023년 8월 11일
0

Javascript

목록 보기
1/1

structuredClone() global function

Javascript에서 객체의 깊은 복사를 위해 여러 방식을 사용했다. Javascript는 이제 structuredClone() 이라는 깊은 복사를 위한 전역 메소드를 지원한다.

전역 structuredClone() 메소드는 깊은 복사를 생성한다.

structuredClone()의 기능을 설명하기 전 얕은 복사와 깊은 복사에 대해 간단하게 설명한다.

얕은 복사

Javascript에서 값을 복사하는 경우 거의 항상 얕은(shallow) 복사이다. 중첩된 객체의 경우 복사된 객체를 변경하면 원본에도 영향을 주게 된다.

Array.prototype.slice

Array.prototype.slice 는 얕은 복사를 수행하기 때문에, 모든 값을 독립적으로 복사할 수 없다.

const arr = [1, 2, [3, 4]];
const copied = arr.slice();

isSameObject(arr, copied); // true

copied[2].push(5);
isSameObject(arr, copied); // true

Spread Operator

펼침 연산자를 통해서도 값의 복사를 수행할 수 있다. 아래 예시와 같이 객체가 이터러블임이 확인이되면 for-loop 과 같은 단순한 반복문을 통해 모든 요소를 하나씩 옮겨 담는다.

const b = [1, 2, 3];
const a = [ ...b ];

// 위를 실행했을 때, 내부적으로 일어나는 일
var a = [];
for (var i = 0; i < b.length; i += 1) {
  a.push(b[i]);
}

이러한 이유로 펼침 연산자 역시 중첩 구조를 복사하지 못한다.

const arr = [1, 2, [3, 4]];
const copied = [ ...arr ];

isSameObject(arr, copied); // true

copied[2].push(5);
isSameObject(arr, copied); // true

Object.assign

Object.assign의 경우에도 마찬가지로 중첩 구조를 복사하지 못한다.

const arr = [1, 2, [3, 4]];
const copied = Object.assign([], arr);

isSameObject(arr, copied); // true

copied[2].push(5);
isSameObject(arr, copied); // true

깊은 복사

깊은(deep) 복사는 얕은 복사의 반댓말로, 복사된 객체를 변경해도 원본에 영향을 주지 않는다. 깊은 복사도 객체의 속성을 하나씩 복사하지만, 다른 객체에 대한 참조를 찾으면 재귀적으로 해당 객체의 복사본도 생성한다.

JSON.parse(JSON.stringify)

JSON.stringify은 입력 값으로 넘어온 데이터를 문자로 변형을 시켜주는 메소드이고, JSON.parse 는 JSON.stringify로 변형된 문자를 다시 원래 객체로 되돌려주는 역할을 한다.

const arr = [1, 2, [3, 4]];
const copied = JSON.parse(JSON.stringify(arr));

isSameObject(arr, copied); // true

copied[2].push(5);
isSameObject(arr, copied); // false

이는 객체 순환을 통해 값을 옮겨담는 과정이 아닌, 문자열로 변경 후 그것을 다시 해석해 원본 객체로 변경하는 과정에서 자바스크립트의 문자열(string) 이라고 불리는 데이터 타입이 immutable primitive type, 즉 불변성의 형질을 띠는 원시 타입이기 때문이다.

이 패턴은 몇가지 단점이 있는데 다음과 같다.

  1. 재귀 데이터 구조: 재귀적인 데이터 구조로 JSON.stringify()를 사용하면 에러가 발생한다.
  2. 내장 함수 유형: Map, Set, Date, RegExp, ArrayBuffer를 포함한 값이 있을 경우 에러가 발생한다.
  3. 함수: 함수를 폐기한다.

기능 및 제한 사항

structuredClone()은 구조적 복제는 순환되는 데이터 구조를 처리할 수 있고, 내장 데이터 타입을 지원할 수 있으며 일반적으로 더 강력하고 더 빠르다.

기능

structuredClone()은 깊은 복사를 하는 데 사용될 수 있으며 아래와 같이 순환 참조도 지원한다.

// 값과 스스로를 순환 참조하는 객체 생성
const original = { name: "MDN" };
original.itself = original;

// 복제
const clone = structuredClone(original);

console.assert(clone !== original); // 동일하지 않은 객체 (같지 않은 동일성)
console.assert(clone.name === "MDN"); // 같은 값을 가집니다.
console.assert(clone.itself === clone); // 순환 참조가 보존됩니다.

structuredClone()를 사용해 객체를 복제하는 경우, 각 객체에 대한 변경은 다른 객체에 영향을 주지 않는다.

const mushrooms1 = {
  amanita: ["muscaria", "virosa"],
};

const mushrooms2 = structuredClone(mushrooms1);

mushrooms2.amanita.push("pantherina");
mushrooms1.amanita.pop();

console.log(mushrooms2.amanita); // ["muscaria", "virosa", "pantherina"]
console.log(mushrooms1.amanita); // ["muscaria"]

제한 사항

  1. 프로토타입: 객체의 프로토타입 체인을 폐기한다.
  2. 함수: 객체에 함수가 있는 경우 폐기된다.
  3. 복제 불가: ErrorDOM 노드는 복제가 불가능하다.

성능

성능 테스트 결과에 따르면 structuredClone()JSON.parse(JSON.stringify) 보다 빠르다는것을 알 수 있다.

브라우저 호환성

Chrome, Edge 등 브라우저에서 모두 사용 가능하다.

결론

Javascript에서 깊은 복사본을 만들어야 하는 경우 다른 라이브러리를 사용하지 않고 자체적으로 제공하는 structuredClone()를 사용하면 될 것 같다.

참고

1개의 댓글

comment-user-thumbnail
2023년 8월 11일

글 잘 봤습니다.

답글 달기