classUser{constructor(publicname: string,publicmeta: object){}}// structuredClone 은 prototype 잃음
constu=newUser('a',{x: 1});constc=structuredClone(u);// c instanceof User === false
// 해결: clone 메서드 직접
classUser{clone():User{returnnewUser(this.name,structuredClone(this.meta));}}
Deep equality
import{dequal}from'dequal';// 또는 lodash isEqual
dequal({a: 1,b:[2]},{a: 1,b:[2]});// true
// Reference equality (===)는 빠르지만 객체 내부 같은지 모름
// JSON.stringify 비교는 키 순서 / NaN / Date 정확 X
Circular safe stringify
import{stringify}from'safe-stable-stringify';// circular 있으면 [Circular] 마커
🤔 의사결정 기준
데이터
도구
Plain object / array / Date / Map / Set
structuredClone
함수 / DOM / class instance
직접 clone 메서드 + structuredClone 재귀
비교 (deep eq)
dequal 또는 lodash isEqual
빠른 immutability + structural sharing
Immer / immutable.js
직렬화 (network, storage)
JSON or msgpack — 의도적 손실 OK
❌ 안티패턴
JSON.parse(JSON.stringify(x)) 를 deep clone default: Date → string, undefined 손실, circular 폭사. 알면서 쓰는 경우만.
Object.assign({}, x) 으로 deep clone 기대: shallow.
{...x} 로 deep clone 기대: shallow.
가변 객체에 structuredClone 매번: 성능. 진짜 필요할 때만 clone.
lodash isEqual 매 렌더: 큰 객체 비교 비용. memo + selector.
NaN === NaN false 예상 못함: deep eq 라이브러리 사용.
TypedArray byteOffset 바뀜: structuredClone OK 지만 이후 backing buffer 다름.
🤖 LLM 활용 힌트
"deep clone = structuredClone, deep eq = dequal" 디폴트.