1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptのstructuredCloneを理解する

1
Posted at

背景

Chakra UI v3 を使ったプロジェクトで Jest のテストを実行したら ReferenceError: structuredClone is not defined で落ちた。Chakra UI v3 が内部で structuredClone を使っているが、Jest の jsdom テスト環境では Node.js ネイティブの structuredClone がグローバルに公開されないことが原因だった

そもそも structuredClone って?、というところから調べたのでまとめる

JavaScript のコピーには3段階ある

そもそもJSのコピーには下記の3種類がある

方法 コピーの深さ 特徴
=(代入) コピーしていない(参照共有) 同じデータを別名で使いたいだけの時
{ ...obj } / [...arr](スプレッド構文) 浅い(1階層目のみ) フラットなオブジェクトのコピー
structuredClone(obj) 深い(全階層) ネストしたデータの完全な複製

代入は「参照の共有」であってコピーではない

const original = { name: "太郎", scores: [80, 90] };
const copy = original;
copy.name = "花子";
console.log(original.name); // "花子" ← 元も変わる

スプレッド構文は1階層目しかコピーしない(シャローコピー)

const original = { name: "太郎", scores: [80, 90] };
const copy = { ...original };
copy.scores.push(100);
console.log(original.scores); // [80, 90, 100] ← ネストした配列は共有されたまま

structuredClone は全階層を完全に複製する(ディープコピー)

const original = { name: "太郎", scores: [80, 90] };
const copy = structuredClone(original);
copy.scores.push(100);
console.log(original.scores); // [80, 90] ← 元は変わらない

structuredCloneJSON.parse/stringify の上位互換

以前のディープコピーの定番だった JSON.parse(JSON.stringify(obj)) と比較すると:

JSON.parse/stringify structuredClone
Date 文字列になって壊れる 正しくコピーされる
Map / Set 消える 正しくコピーされる
undefined 消える 正しくコピーされる
RegExp 空オブジェクト {} になる 正しくコピーされる
循環参照 エラーで落ちる 正しくコピーされる

Jest で structuredClone is not defined になる問題と解決策

Jest の jsdom テスト環境では Node.js ネイティブの structuredClone がグローバルに公開されない。そのため Chakra UI v3 のようにこれを使うライブラリがあるとテストが落ちる

対処として jest.setup.tsJSON.parse/stringify ベースの簡易ポリフィルを追加して解決した

// jest.setup.ts に追加したポリフィル
if (typeof globalThis.structuredClone === "undefined") {
  globalThis.structuredClone = <T>(val: T): T =>
    JSON.parse(JSON.stringify(val));
}

Chakra UI 内部ではプレーンなオブジェクトしかクローンしないため、JSON 方式の弱点(Date, Map 等の非対応)には当たらない。だからこの簡易ポリフィルで十分

まとめ

  • JavaScript のコピーは「参照共有」「シャローコピー」「ディープコピー」の3段階がある
  • structuredCloneJSON.parse/stringify の上位互換で、Date, Map, 循環参照なども正しくコピーできる
  • Jest の jsdom 環境では structuredClone がグローバルに公開されないので、ポリフィルが必要

感想

  • スプレッド構文の性質については初めて知った、びっくり

参考

1
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?