structuredClone() โ Web Platform์ด ์ ๊ณตํ๋ ํ์ค ๋ฅ ํด๋ก
๐ 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๋ฅผ ์ํํ ์ ์๋ค๋ ์ ์ด ๊ฐ์ฅ ํฐ ์ฅ์ ์ผ๋ก ๋๊ปด์ง๋ค.