structuredClone으로 안전하게 깊은 복사하기
JavaScript에서 객체를 복사할 때 전개 문법을 사용하면 최상위 속성만 복사됩니다. 내부에 객체나 배열이 있으면 원본과 복사본이 같은 참조를 공유하기 때문에, 중첩 값을 변경했을 때 원본까지 바뀔 수 있습니다.
const original = {
profile: {name: 'Kim'},
};
const copied = {...original};
copied.profile.name = 'Lee';
console.log(original.profile.name); // 'Lee'JSON 변환 방식의 한계
과거에는 JSON.stringify()와 JSON.parse()를 조합해 깊은 복사를 구현하는 경우가 많았습니다.
const copied = JSON.parse(JSON.stringify(original));하지만 이 방식은 Date, Map, Set 같은 값을 원래 타입 그대로 보존하지 못합니다. undefined와 함수는 사라질 수 있으며 순환 참조가 포함된 객체는 직렬화 과정에서 오류가 발생합니다.
structuredClone 사용하기
structuredClone()은 브라우저와 최신 Node.js에서 제공하는 구조화 복제 API입니다. 중첩 객체뿐 아니라 여러 내장 타입과 순환 참조도 처리할 수 있습니다.
const original = {
createdAt: new Date(),
tags: new Set(['javascript', 'web']),
profile: {name: 'Kim'},
};
const copied = structuredClone(original);
copied.profile.name = 'Lee';
console.log(original.profile.name); // 'Kim'
console.log(copied.createdAt instanceof Date); // true
console.log(copied.tags instanceof Set); // true복사할 수 없는 값
모든 값을 복사할 수 있는 것은 아닙니다. 함수와 DOM 노드처럼 구조화 복제 알고리즘에서 지원하지 않는 값이 포함되면 DataCloneError가 발생합니다.
const value = {
handler: () => console.log('click'),
};
structuredClone(value); // DataCloneError전송 가능한 객체 이전하기
ArrayBuffer처럼 전송 가능한 객체는 transfer 옵션을 사용해 복사 대신 소유권을 이동할 수 있습니다. 큰 바이너리 데이터를 워커로 넘길 때 불필요한 메모리 복사를 줄이는 데 유용합니다.
const buffer = new ArrayBuffer(1024);
const copied = structuredClone(buffer, {
transfer: [buffer],
});
console.log(buffer.byteLength); // 0
console.log(copied.byteLength); // 1024정리
전개 문법은 중첩 객체까지 복사하지 않습니다.
JSON 변환 방식은 타입 손실과 순환 참조 문제가 있습니다.
structuredClone()은 다양한 내장 타입과 순환 참조를 지원합니다.함수와 DOM 노드 등 일부 값은 복사할 수 없습니다.
상태를 갱신할 때는 무조건 깊은 복사하기보다 필요한 경로만 불변하게 변경하는 편이 효율적입니다.

댓글 0