Node.js で structuredClone グローバル関数が使えるようになる
◆ グローバル変数の structuredClone が Node.js に実装された
◆ まだ master ブランチのみで最新リリースに含まれてない
◆ whatwg スペックにあるけどブラウザではまだ実装予定がなさそう
◆ まだ master ブランチのみで最新リリースに含まれてない
◆ whatwg スペックにあるけどブラウザではまだ実装予定がなさそう
クローンが大変
他と共有してるデータだから元データは変更したくない というときにはデータをクローンしたいのですが JavaScript ってデータのクローンが面倒です// shallow copy
const clone = {...original}
// prototype chain
const clone = Object.create(original)
こういう方法で十分なケースもありますが ネストされた深い部分のオブジェクトのプロパティを書き換えたいとなると オブジェクトを再帰してプロパティをクローンしていくことになります
コードを短く書くだけなら
const clone = JSON.parse(JSON.stringify(original))
のように JSON 化してパースすればよいですが パフォーマンス的には再帰してコピーするのに比べると遅いです
たまに小さいデータをクローンするならこれで済ますこともありますが できればちゃんとした再帰してコピーする方法にしておきたいです
かと言ってそのコードを書くのも少しめんどうです
また 自作するならどこまでクローンするかも問題になります
JSON 表現できるものだけにして getter があるならそれで取得できた値をクローンにセットするのか
getter/settter や writable や enumerable などのプロパティ定義も含めてクローンするのか
クローン側でも循環参照を再現させるのか
関数の扱いはどうするのか
getter/setter などは Object.getOwnPropertyDescriptors で取得した descriptor をクローン先にセットすればいいので 簡単に済みますが循環参照の対応もするとなると大変です
関数は関数定義の文字列から再作成してもスコープが引き継がれません
親スコープを見ずに引数だけで返り値が決まる関数でないとエラーです
イミュータブルなので参照そのものをコピーしてもよいのですが 関数のプロパティに独自の値を持たせる場合は共有されてしまいます
内部的に元の関数を呼びだす新しい関数を作るとかでしょうか
クローンのクローンのクローンの……という関数なら実行時に呼び出す関数の数がすごいことになりそうです
そういった問題が色々あってクローンは簡単ではないです
Structured clone algorithm
JSON 化してパースに近いものですが JavaScript で使われている公式なクローンアルゴリズムがあります直接クローンするために使うものではなく データの受け渡し時に内部的に使われるものです
window 間や window と worker 間のデータの受け渡しなどで使われます
window.onmessage = event => console.log(event.data)
window.postMessage({ a: 1, b: [2, 3, { c: null, d: undefined }] })
{...}
a: 1
b: Array(3)
0: 2
1: 3
2: {c: null, d: undefined}
別の JavaScript 空間に渡すのが目的なので Symbol や関数はクローンできなくなってます
実行するとこういうエラーが発生します
Uncaught DOMException: Failed to execute 'postMessage' on 'Window': Symbol() could not be cloned.
Uncaught DOMException: Failed to execute 'postMessage' on 'Window': () => {} could not be cloned.
この postMessage/onmessage の処理でクローンすることもできるのですが window にメッセージを送っているのでクローン目的以外の処理も影響を受けます
type プロパティを必須にして type に clone が入っていたらクローン処理でハンドルするとかもできますが 専用のチャンネルを作ってしまうほうが良いです
const {port1, port2} = new MessageChannel()
port1.onmessage = event => console.log(event.data)
port2.postMessage({x:1})
ですがクローンするだけにこれは面倒なものです
普通の関数としてクローン関数があればなと思ってました
探してみると whatwg のスペックでは WindowOrWorkerGlobalScope のプロパティ(グローバル変数)として structuredClone が存在します
https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope-mixin
ブラウザで使えることを期待したのですが window.structuredClone を実行しても関数がみつかりませんでした
Chrome Status でリリース予定の機能を見てもこの先の数バージョンでそれらしいのはみつかりませんでした
内部的には存在するアルゴリズムでそれを公開するだけなので急に追加されるのかもですが 今のところはブラウザで使える予定はなさそうです
Node.js
ブラウザではいつ実装されるのかわからない状態ですが Node.js ではつい最近実装されましたhttps://github.com/nodejs/node/commit/d0a898681f8d5a5fcd53fa2ab8e0a3da807791be
1 週間前のコミットなのでまだ master にしかなく最新版のリリースでも含まれてません
16 の LTS 化のときまでにはリリースに含まれてそうです