structuredClone() โ€“ Web Platform์ด ์ œ๊ณตํ•˜๋Š” ํ‘œ์ค€ ๋”ฅ ํด๋ก 

๐Ÿ“š
Web
2025.11.16

๐Ÿ“š Overview

structuredClone()์€ ๊ฐ’ ์ „์ฒด๋ฅผ ๊นŠ์€ ๋ณต์‚ฌ(Deep Copy) ํ•ด์ฃผ๋Š” Web Platform API๋‹ค. JSON.parse(JSON.stringify(...)) ๋‚˜ lodash.cloneDeep ๊ฐ™์€ ์šฐํšŒ ๋ฐฉ๋ฒ• ์—†์ด, ์›น ํ‘œ์ค€ API๋กœ ๊ณต์‹ ์ง€์›ํ•˜๋Š” ๋”ฅ ํด๋ก  ๋„๊ตฌ๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์•„๋ž˜ ๋‚ด์šฉ์„ ๋‹ค๋ค„ ๋ณผ ์˜ˆ์ •์ด๋‹ค.

  • structuredClone()์€ ์–ด๋–ค ํ‘œ์ค€์— ์†ํ•˜๋Š”๊ฐ€?
  • ๊ธฐ๋ณธ ๋ฌธ๋ฒ•๊ณผ ๋™์ž‘ ๋ฐฉ์‹
  • JSON.stringify๊ณผ์˜ ๋น„๊ต
  • ์‹ค๋ฌด์—์„œ ํ™œ์šฉ ์‚ฌ๋ก€


1. structuredClone()์€ ์–ด๋”” ํ‘œ์ค€์— ์†ํ• ๊นŒ?


๋จผ์ € ์งš๊ณ  ๊ฐˆ ๋‚ด์šฉ์€ structuredClone()์€ ES ํ‘œ์ค€(ECMAScript Language Specification)์— ์ •์˜๋œ ๋ฌธ๋ฒ•์ด ์•„๋‹ˆ๋‹ค.

structuredClone()์€ let, class, Promise, Array.prototype.map์ฒ˜๋Ÿผ ECMAScript๊ฐ€ ์ •์˜ํ•œ โ€œ์–ธ์–ด ์ž์ฒด์˜ ๊ธฐ๋Šฅโ€์ด ์•„๋‹ˆ๋‹ค.

์˜คํžˆ๋ ค fetch์ฒ˜๋Ÿผ ๋ธŒ๋ผ์šฐ์ €(Web Platform)๊ฐ€ ํ™˜๊ฒฝ ์ฐจ์›์—์„œ ์ œ๊ณตํ•˜๋Š” API์— ๋” ๊ฐ€๊น๋‹ค. ์ฆ‰, JavaScript ๋ฌธ๋ฒ•์— ํฌํ•จ๋œ ๊ธฐ๋Šฅ์ด ์•„๋‹ˆ๋ผ ๋ธŒ๋ผ์šฐ์ €๋‚˜ Node.js๊ฐ€ ๊ตฌํ˜„ํ•œ Web API๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

๋”ฐ๋ผ์„œ ์ด๋Ÿฐ ์ฝ˜์†”์—์„œ๋„ ๊ฐ„ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.


MDN์—์„œ๋„ Window: structuredClone() method์™€ WorkerGlobalScope: structuredClone() method๋กœ ๊ฐ๊ฐ ๋ฌธ์„œํ™”๋˜์–ด ์žˆ์œผ๋ฉฐ, ํ•ด๋‹น ๋‚ด์šฉ์€ ๊ฒฐ๊ตญ WHATWG์˜ HTML Standard์—์„œ ์ •์˜ํ•œ ๊ตฌ์กฐํ™” ๋ณต์ œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ๋‹ค.

๐Ÿ’ก structuredClone()์ด ์†ํ•œ ์ŠคํŽ™์€ WHATWG HTML Standard๋‹ค.
WHATWG(์›น ํ•˜์ดํผํ…์ŠคํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ์ˆ  ์›Œํ‚น ๊ทธ๋ฃน)๋Š” HTML, DOM, Fetch ๊ฐ™์€ ์›น ํ”Œ๋žซํผ ํ•ต์‹ฌ ํ‘œ์ค€์„ ์ •์˜ํ•˜๋Š” ๋‹จ์ฒด๋กœ, ๋ธŒ๋ผ์šฐ์ €๋“ค์ด ๊ณตํ†ต์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” โ€œ์‹ค์ œ ์›น ํ‘œ์ค€โ€์„ ๋งŒ๋“ ๋‹ค.

structuredClone() ์—ญ์‹œ ์ด HTML Standard์— ํฌํ•จ๋œ Structured Clone Algorithm์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ œ๊ณต๋˜๋Š” Web API๋‹ค.



2. ๊ธฐ๋ณธ ๋ฌธ๋ฒ•


https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone

  • value: ๋ณต์ œํ•  ๊ฐ’. structured-cloneable ํƒ€์ž…์ด๋ผ๋ฉด ๋Œ€๋ถ€๋ถ„ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • options(transfer): ๋ณต์ œ ๋Œ€์‹  โ€œ์†Œ์œ ๊ถŒ์„ ๋„˜๊ธธโ€ ๊ฐ์ฒด ๋ฆฌ์ŠคํŠธ (ArrayBuffer ๋“ฑ Transferable ํƒ€์ž…).
// ๊ธฐ๋ณธ ํ˜•ํƒœ
structuredClone(value);

// Transferable objects ์˜ต์…˜์„ ํ•จ๊ป˜ ๋„˜๊ธธ ๋•Œ
structuredClone(value, {
  transfer: [/* ArrayBuffer, ImageBitmap ... */],
});

structuredClone()์˜ ๋ฐ˜ํ™˜ ๊ฐ’์€ ํ•ญ์ƒ ์›๋ณธ๊ณผ ๋ถ„๋ฆฌ๋œ ๊นŠ์€ ๋ณต์‚ฌ(Deep Copy) ์ด๋‹ค.


๐Ÿ’ก Transferable objects ๋ž€?

Transferable objects๋Š” ๋ง ๊ทธ๋Œ€๋กœ โ€œ๋ณต์‚ฌํ•˜๋Š” ๋Œ€์‹  ์†Œ์œ ๊ถŒ์„ ์ด๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๊ฐ’โ€ ์„ ์˜๋ฏธํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ArrayBuffer ๊ฐ™์€ ๋Œ€์šฉ๋Ÿ‰ ๋ฒ„ํผ๋ฅผ ์ƒ๊ฐํ•ด๋ณด๋ฉด, ๋ณต์‚ฌํ•˜๋ ค๋ฉด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋˜ ๋งŒ๋“ค์–ด์•ผ ํ•˜๊ณ  ์‹œ๊ฐ„๋„ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ฒŒ ๋œ๋‹ค.

๊ทธ๋ž˜์„œ ๋ธŒ๋ผ์šฐ์ €๋Š” โ€œ๋ณต์‚ฌํ•˜์ง€ ๋ง๊ณ  ๊ทธ๋ƒฅ ์†Œ์œ ๊ถŒ์„ ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ ์˜ฎ๊ฒจ๋ฒ„๋ฆฌ๋Š” ๋ฐฉ์‹โ€์„ ์ง€์›ํ•œ๋‹ค. ์ฆ‰, Transferable๋กœ ์ง€์ •ํ•˜๋ฉด ๋ณต์‚ฌํ•˜์ง€ ์•Š์•„๋„ ๋˜๋ฏ€๋กœ ์„ฑ๋Šฅ์ƒ ์ด์ ์ด ์žˆ๊ฒŒ๋œ๋‹ค.

๋‹จ, ์›๋ž˜ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋˜ ๊ณณ์—์„œ๋Š” ์ด ๊ฐ’์„ ๋” ์ด์ƒ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.



3. ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด๋„ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณต์‚ฌ


structured clone ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋‚ด๋ถ€์—์„œ ์ฐธ์กฐ๋ฅผ ๊ธฐ๋กํ•˜๋ฉฐ ์ˆœํ™˜ ๊ตฌ์กฐ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm

const original = { name: 'structured clone' };
original.self = original; // ์ˆœํ™˜ ์ฐธ์กฐ

const cloned = structuredClone(original);

console.log(cloned === original);        // false (๋‹ค๋ฅธ ๊ฐ์ฒด)
console.log(cloned.name);                // 'structured clone'
console.log(cloned.self === cloned);     // true (์ˆœํ™˜ ๊ตฌ์กฐ ์œ ์ง€)

์ด ๋ถ€๋ถ„์ด JSON.parse(JSON.stringify(obj))์™€ ๊ฐ€์žฅ ํฐ ์ฐจ์ด ์ค‘ ํ•˜๋‚˜๋‹ค.



4. JSON.parse(JSON.stringify(โ€ฆ))์™€ ๋น„๊ต


const deepCopied = JSON.parse(JSON.stringify(value));

์œ„ ๋ฌธ๋ฒ•์˜ ์žฅ์ ์€ ๋‹จ์ˆœํ•จ์ด์ง€๋งŒ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ๊ฐ€์ง„๋‹ค.

  • ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ์žˆ์œผ๋ฉด JSON.stringify() ๋‹จ๊ณ„์—์„œ ์˜ˆ์™ธ ๋ฐœ์ƒ
  • Map, Set, Date, RegExp, ArrayBuffer ํƒ€์ž…์€ ๊นจ์ง€๊ฑฐ๋‚˜ ๋ฌธ์ž์—ดํ™”
  • ํ•จ์ˆ˜๋Š” ์ œ๊ฑฐ๋จ

ํ•˜์ง€๋งŒ structuredClone()์€ ์œ„์— ์—ด๊ฑฐํ•œ ๋‹จ์ ๋“ค์ด ์ƒ๋‹น ๋ถ€๋ถ„ ๋ณด์™„๋œ๋‹ค.

ํ•ญ๋ชฉ JSON ๊ธฐ๋ฐ˜ ๋”ฅ ํด๋ก (JSON.stringify) structuredClone()
์ˆœํ™˜ ์ฐธ์กฐ โŒ ์ˆœํ™˜ ๊ตฌ์กฐ ๋ฐœ๊ฒฌ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ โœ… ์ˆœํ™˜ ์ฐธ์กฐ ๊ทธ๋Œ€๋กœ ๋ณต์ œ ๊ฐ€๋Šฅ
Map / Set / Date / RegExp / ArrayBuffer ๋“ฑ โŒ ๋Œ€๋ถ€๋ถ„ ๋ฌธ์ž์—ดํ™”๋˜๊ฑฐ๋‚˜ ์ผ๋ฐ˜ ๊ฐ์ฒด๋กœ ๋ณ€ํ˜• โœ… ์ŠคํŽ™์— ์ •์˜๋œ ๋ฐฉ์‹์œผ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ณต์ œ๋จ
ํ•จ์ˆ˜(Function) โญ• ์˜ค๋ฅ˜ ์—†์ด ํฌํ•จ๋˜์ง€๋งŒ ๊ทธ๋ƒฅ ์ œ๊ฑฐ๋จ โŒ ํฌํ•จ ์‹œ DataCloneError ์˜ˆ์™ธ ๋ฐœ์ƒ
ํƒ€์ž… ๋ณด์กด โŒ ๋‹จ์ˆœ ๊ฐ์ฒด/๋ฐฐ์—ด๋งŒ ์ œ๋Œ€๋กœ ๋ณด์กด โœ… Map, Set ๋“ฑ ๋‹ค์–‘ํ•œ Web/JS ํƒ€์ž… ๋ณด์กด

๐Ÿ’ก ํ•จ์ˆ˜(Function)๋Š” ๋ณต์ œํ•  ์ˆ˜ ์—†๋‹ค

structuredClone()์€ ํ•จ์ˆ˜, ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ์™€ ๊ฐ™์€ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ(executable code) ๋Š” ๋ณต์ œํ•˜์ง€ ๋ชปํ•œ๋‹ค. ์ด๋Ÿฐ ๊ฐ’์ด ํฌํ•จ๋œ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ์กฐ์šฉํžˆ ๋ฌด์‹œ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ DataCloneError (DOMException) ๋ฅผ ๋ฐ”๋กœ ๋˜์ง„๋‹ค.



5. ์‹ค๋ฌด์—์„œ ์–ธ์ œ ์“ฐ๋ฉด ์ข‹์„๊นŒ?


API ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋‹ค ๋ณด๋ฉด ์›๋ณธ ์š”์ฒญ ๊ฐ’(req.body)์„ ๊ทธ๋Œ€๋กœ ๋‚จ๊ฒจ๋‘๊ณ , ๋ณ„๋„๋กœ ๊ฐ€๊ณตํ•œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋กœ๊น…, ๊ฒ€์ฆ, ๋‚ด๋ถ€ ์‹œ์Šคํ…œ ์ „๋‹ฌ์šฉ DTO ๋“ฑ์„ ๋งŒ๋“ค ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

const original = req.body;                 // ์›๋ณธ์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€
const payload = structuredClone(req.body); // ๊ฐ€๊ณต์šฉ ๊นŠ์€ ๋ณต์‚ฌ ๊ฐ์ฒด

payload.flag = true;
process(payload);

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์›๋ณธ ๊ฐ’์„ ์˜ค์—ผ์‹œํ‚ค์ง€ ์•Š๊ณ  ๊นจ๋—ํ•œ ๋ณต์ œ๋ณธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ›„์ฒ˜๋ฆฌ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.



๐Ÿค” Understanding

structuredClone()์€ ๊ฐ์ฒด๋ฅผ ๊นŠ๊ฒŒ ๋ณต์‚ฌํ•˜๊ธฐ ์œ„ํ•ด Web Platform์ด ์ œ๊ณตํ•˜๋Š” ํ‘œ์ค€ ๊นŠ์€ ๋ณต์‚ฌ API์ž„์„ ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค.

๊ธฐ์กด์— ์‚ฌ์šฉ๋˜๋˜ JSON.parse(JSON.stringify()) ๋ฐฉ์‹์ด ๊ฐ€์ง„ ํ•œ๊ณ„(ํƒ€์ž… ์†์‹ค, ์ˆœํ™˜ ์ฐธ์กฐ ์˜ˆ์™ธ ๋“ฑ)๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ , ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด๋„ ๋ธŒ๋ผ์šฐ์ €์™€ Node.js์—์„œ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ํ‘œ์ค€ํ™”๋œ Deep Copy๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ๊ฐ€์žฅ ํฐ ์žฅ์ ์œผ๋กœ ๋А๊ปด์ง„๋‹ค.

Previous
Object.groupBy / Map.groupBy (ES2024)
๐Ÿ“šJavaScript
2025.11.08
Next
MikroORM v6.6 โ€“ ๋ฌด์—‡์ด ๋‹ฌ๋ผ์กŒ๋‚˜?
๐Ÿ“šBackend
2025.12.01