解説
配列やオブジェクトのように、内部の要素に参照を持っているデータを複製する場合は注意が必要です。
シャローコピーと呼ばれる複製法では、値はそのまま複製しますが、参照は「参照を複製」します。そのため、コピー元で参照先を書き換えると、コピー先でも参照先が書き換わります。
コピー元 コピー先 ┏配列━┓ ┏配列━┓ ┃・参照╂──┐┌───╂・参照┃ ┃・値 ┃ ┏配列━┓ ┃・値 ┃ ┃・値 ┃ ┃・値 ┃ ┃・値 ┃ ┗━━━┛ ┃・値 ┃ ┗━━━┛ ┃・値 ┃ ┗━━━┛
ディープコピーと呼ばれる複製法では、値を複製するだけでなく、「参照先も複製」します。そのため、コピー元で参照先を書き換えても、コピー先では影響をうけません
コピー元 コピー先 ┏配列━┓ ┏配列━┓ ┃・参照╂──┐ ┃・参照╂──┐ ┃・値 ┃ ┏配列━┓ ┃・値 ┃ ┏配列━┓ ┃・値 ┃ ┃・値 ┃ ┃・値 ┃ ┃・値 ┃ ┗━━━┛ ┃・値 ┃ ┗━━━┛ ┃・値 ┃ ┃・値 ┃ ┃・値 ┃ ┗━━━┛ ┗━━━┛
サンプル
シャローコピーとディープコピーの様子が分かるコードを、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]]
