JavaScript에서 값을 복사할때는 항상 얕은 복사 (shallow copy)를 수행한다. 따라서 primitive data type (string, number, bigint, boolean, undefined, symbol등) 이 아닌 경우 객체의 참조로 처리된다. 얕은 복사의 반대는 깊은 복사 (deep copy)인데, 이는 복사 중 다른 객체를 참조를 찾으면 재귀적으로 참조의 내용도 찾아 복사를 수행한다. 이렇게 참조가 있는 한 객체를 깊은 복사하는 것은 꽤 까다로운 일이다. 결과물인 복사된 객체에서 원본이 가르키는 어떤 참조도 중첩하여 갖게해서는 안되기 때문이다.
JavaScript에서는 이러한 깊은 복사를 수행하는 제공되지 않는다. 그래서, 오랜동안
JSON.stringify/parse
를 이용한 일종의 트릭을 이용한 깊은 복사 방법을 제공하는
라이브러리에 의존해왔다.
그러나 Web Platform에서는 IndexedDB 저장이나, WebWorker간 MessageChannel 메세지 전송등의 Spec.을 구현하고자 할때 JavaScript 직렬화/역직렬화 방법이 필요하였다. 이를 구현한 것이 structuredClone이며, 함수 내부적으로 복사를 어떻게 수행하는지는 structured clone algorithm이라고 부르는 Spec.에 의해 정의되어있다. 모든 타입의 JavaScript 객체가 이 알고리즘에 의해 처리되는 것은 아니며, JavaScript 의 Builtin Type뿐 아니라 Web Spec. 정의된 일부 객체들도 복사가 가능하도록 되어있다.
API
API의 사용 방법은 아래와 같은데, 두번째 파라미터가 정의되었을 때의 동작이 눈여겨 볼만하다.
1 | structuredClone(value); |
첫번째 파라미터는 structured clone algorithm이 지원하는 타입의 복사본을 만든다.
2번째 파라미터 optional 한 option 값인데 현재
options.transfer : Array
를 지원한다. 이 옵션을 통해 전달되는 값은 Transferable objects의 배열이 가능하며, Transferable objects의 대표적인 타입으로는 ArrayBuffer, Readable/WritableStream등이 있다. 복사가 아닌 transfer를 이용할 때의 장점은 두가지를 들 수 있다.소유권의 이전 - transfer 되는 리소스를 하나의 JavaScript Context에서만 사용할 수 있게 소유권을 제한할 수 있다.
성능 - transfer 객체와 환경에 따라 zero-copy operation을 이용하여 빠르게 다른 context로 넘길 수 있다. 이는 특히 WebWorker와 같이 한 thread에서 다른 thread로 데이터를 넘길때 유용하다.
1 | const buffer1 = new ArrayBuffer(16); |
1 | const object1 = { |