Posted at

JavaScriptのDeepCopyでJSON.parse/stringifyを使ってはいけない

More than 3 years have passed since last update.

JavaScriptでのDeepCopyはJqueryではextend, angular.js だと angular.copy を使って簡単にできてしまうようだけれど、標準実装としてはそもそも用意がされていないようだ。

だから自分で作らないと行けないし、それにはいくつもの方法があって、中には罠のようなものもある。

例えば適当に個人ブログなんかを当たって見つかるのがJSONを経由した方法。

var copy = JSON.parse(JSON.stringify(obj));

オブジェクトをJSON文字列に変換してから再びオブジェクトに戻すというハック的なやり方だ。stackoverflowだとこれが一番高速に動くぜ!なんて意見もあって、さすがネイティブ実装されたメソッドなだけはあるという感じだ。お手軽感も高い。

しかしDeepCopyする方法として実戦投入するにはいくつかの問題がある。


①そもそもDeepCopyするためのものじゃない

 この方法を知らない他人がコードを見たときに「ああ、DeepCopyをしてるんだな」とはすぐに気づけないだろう。


②破壊的な変換を伴う

 JSON.stringify()を行ったときに破壊的な変換が行われてしまう可能性がある。

 オブジェクトのプロパティに以下の3種類が入っている場合だ。


Dateオブジェクト

var d = new Date(); // Wed Aug 05 2015 21:47:25 GMT+0900 (JST)

JSON.stringify(d); // "2015-08-05T12:47:25.328Z"


function

JSON.stringifyするとなぜか消えてしまう。


undefined

これもfunction同様、stringifyによって消されてしまう。

よって以下のオブジェクトをJSON.parse/stringifyでDeepCopyしようとすると悲惨な目に遭う。

変換前

// コピーするオブジェクト

var obj = {
p: "hoge",
d: Wed Aug 05 2015 22:23:40 GMT+0900 (JST),
u: undefined,
f: function(){}
}

// DeepCopyしたつもり
var copy = JSON.parse(JSON.stringify(obj));
// {p: "hoge", d: "2015-08-05T13:23:40.864Z"} ごっそり抜け落ちる

3種類と書いたが他にもあるのかもしれない。 何にせよ、軽々しく使ってはいけない方法だろう。

参考

[stackoverflow] Most elegant way to clone a JavaScript object

[stackoverflow] What is the most efficient way to clone an object?