解説
配列やオブジェクトのように、内部の要素に参照を持っているデータを複製する場合は注意が必要です。
シャローコピーと呼ばれる複製法では、値はそのまま複製しますが、参照は「参照を複製」します。そのため、コピー元で参照先を書き換えると、コピー先でも参照先が書き換わります。
コピー元 コピー先 ┏配列━┓ ┏配列━┓ ┃・参照╂──┐┌───╂・参照┃ ┃・値 ┃ ┏配列━┓ ┃・値 ┃ ┃・値 ┃ ┃・値 ┃ ┃・値 ┃ ┗━━━┛ ┃・値 ┃ ┗━━━┛ ┃・値 ┃ ┗━━━┛
ディープコピーと呼ばれる複製法では、値を複製するだけでなく、「参照先も複製」します。そのため、コピー元で参照先を書き換えても、コピー先では影響をうけません
コピー元 コピー先 ┏配列━┓ ┏配列━┓ ┃・参照╂──┐ ┃・参照╂──┐ ┃・値 ┃ ┏配列━┓ ┃・値 ┃ ┏配列━┓ ┃・値 ┃ ┃・値 ┃ ┃・値 ┃ ┃・値 ┃ ┗━━━┛ ┃・値 ┃ ┗━━━┛ ┃・値 ┃ ┃・値 ┃ ┃・値 ┃ ┗━━━┛ ┗━━━┛
サンプル
シャローコピーとディープコピーの様子が分かるコードを、JavaScriptで簡単に書いてみます。
<html> <head> <title>「シャローコピーとディープコピー」のサンプル</title> </head> <body> <pre><script type="text/javascript"> var arr1 = [ [0, 1, 2] ,[3, 4, 5] ,[6, 7, 8] ]; document.writeln("元配列 : " + dump(arr1) + "\n"); // シャローコピー var arr2 = shallow(arr1); function shallow(arr) { var res = []; for (var i = 0; i < arr.length; i ++) { res[i] = arr[i]; } return res; } arr1[0][0] = 99; document.writeln("シャローコピー"); document.writeln("コピー元配列 : " + dump(arr1)); document.writeln("コピー先配列 : " + dump(arr2) + "\n"); // ディープコピー var arr3 = deep(arr1); function deep(arr) { var res = []; for (var i = 0; i < arr.length; i ++) { if (arr[i] instanceof Array) { res[i] = deep(arr[i]); } else { res[i] = arr[i]; } } return res; } arr1[0][0] = 999; document.writeln("ディープコピー"); document.writeln("コピー元配列 : " + dump(arr1)); document.writeln("コピー先配列 : " + dump(arr3) + "\n"); // 出力用 function dump(arr) { return "[[" + arr.join("],[") + "]]"; } </script></pre> </body> </html>
元配列 : [[0,1,2],[3,4,5],[6,7,8]] シャローコピー コピー元配列 : [[99,1,2],[3,4,5],[6,7,8]] コピー先配列 : [[99,1,2],[3,4,5],[6,7,8]] ディープコピー コピー元配列 : [[999,1,2],[3,4,5],[6,7,8]] コピー先配列 : [[99,1,2],[3,4,5],[6,7,8]]