JavaScriptでオブジェクトをdeep copyする方法

プログラミング

JavaScriptにもJavaやC#と同じように参照型変数が存在し、オブジェクトや配列、関数が参照型変数です。
そして、JavaやC#と同じように、単純に「=」で代入するだけでは参照先(オブジェクトのメモリ領域を示すポインタ)しかコピーできず、コピー先の変更がコピー元に影響してしまいますし、その逆にコピー元の変更がコピー先に影響してしまいます。
(このようなコピーを「シャローコピー(浅いコピー)」と呼びます)

これを避けたい場合には、参照しているメモリの中身を丸ごとコピー(新たにメモリ領域を確保し書き込み)する必要があります。 (このようなコピーを「ディープコピー(深いコピー)」と呼びます)
JavaScriptでは標準でディープコピーを行うための関数が用意されていないので、自力で実装するか、外部のライブラリを使用するかする必要があります。
今回は、deepcopyというライブラリを使用します。
(なお、ディープコピーをサポートするライブラリは他にもあり、用途に応じて使い分けた方が良いです。JSONでシリアライズ・デシリアライズする方法もありますが、関数やundefinedがコピーされない等の問題があるので注意が必要です。)

以下、サンプルコードです。
Node.jsを使用して検証します。

【事前準備】

・Node.js command prompt を起動

・作業フォルダ(今回は”C:\tmp\”)に移動

cd c:\tmp\

・deepcopyライブラリをインストール

npm install deepcopy

【サンプルコード】

サンプルコードは作業フォルダ直下に作成します。

・ShallowCopy.js

let item1 = {id:1, name:"Sword"};
let item2 = item1;
item2.id = 2; // オブジェクトのコピー
item2.name = "Shield";
console.log(item1);
console.log(item2); 

・DeepCopy.js

const deepcopy = require('deepcopy'); // コピー用ライブラリ読込
let item1 = {id:1, name:"Sword"};
let item2 = deepcopy(item1); // オブジェクトのコピー
item2.id = 2;
item2.name = "Shield";
console.log(item1);
console.log(item2); 

実行結果】

c:\tmp>node ShallowCopy.js
{ id: 2, name: 'Shield' }
{ id: 2, name: 'Shield' }

c:\tmp>node DeepCopy.js
{ id: 1, name: 'Sword' }
{ id: 2, name: 'Shield' }

c:\tmp>

いかがでしたでしょうか?

JavaScriptのディープコピーは実務でも誤りやすいポイントであり、関数が含まれるオブジェクトをJSONのシリアライズ・デシリアライズでディープコピーしてしまいバグになる所を実際に目にしたこともあります。
ディープコピーの方法は今回紹介した方法以外にも色々あるので、現場毎で確認すると良いでしょう。

コメント

タイトルとURLをコピーしました