まずはこのコードを見てください。
JavaScript
1var a = [100];
2var b = a;
3console.log(a === b); // true <- わかる
4console.log(a === [100]); // false <- !?!?!?
JavaScriptの世界ではArrayやObject等は生成時に唯一の目に見えないID(以下ユニークID)
が与えられます。
ユニークIDの実体はオブジェクトが格納されているメモリ空間上のアドレスです。
var a = [100]
には配列の実体そのものではなく、メモリ空間上のアドレス、つまりユニークIDという特殊な数値が代入されています。
[100] === [100]
は[100]
という配列を2個生成して、それぞれにユニークIDを割り振ります。
オブジェクト同士の比較演算では、このユニークID同士のみを比較します。
ユニークID以外は完全に一致する2つの[100]
ですが、ユニークIDが異なる為にfalse
になるのです。
※ユニークIDと連呼していますが、これは説明し易いから呼んでいるだけで正式な名称ではありません。この回答文以外ではメモリ空間のアドレス等の名称で呼んで下さい。
この現象は配列やオブジェクト操作の時にも影響されます。
JavaScript
1var a = [1];
2var b = [1];
3a[0] = 2;
4console.log(a, b); // [2], [1] <- わかる
5
6var c = b;
7c[0] = 3;
8console.log(a, b, c); // [2], [3], [3] <- !?!?!?
配列やオブジェクトの値を操作する場合、ユニークIDに従ってメモリ空間上にある値を直接更新します。
その結果、上記のコードではc[0]
の変更の影響がb[0]
に出ています。
ちなみにaとbは別々に配列を作っていますので相互不干渉です。
この仕様、一部のケースではとても困ります。
- 失敗したら変更操作を取り消したい
- 変更前後で比較検証したい
配列やオブジェクトのプロパティを操作したら本物に影響が出てしまうわけですからね。
そこで、全くのクローンを生成する手法が用意されていたり、編み出されています。
分かりやすい簡単なコードはこれです。
JavaScript
1var a = [1, 2, 3, 4, 5];
2var b = [];
3for (var i = 0; i < a.length; i++) {
4 b.push(a[i]);
5}
6
7b[0] = 10;
8console.log(a, b); // [1, 2, 3, 4, 5], [10, 2, 3, 4, 5]
aとbは別々の配列を作る宣言をしていますので、ユニークIDは別個です。
その後a配列の要素を一つずつbにコピーしていますが、
aとbは既に切り離されていますし、a配列の要素は全て数値なのでユニークIDのコピーは発生しません。
bはaのクローンを作る事に成功したのです。
従って、a配列には影響を与えずにb[0] = 10
と意図通りの操作を行う事に成功しています。
この手法は「シャローコピー」、「ディープコピー」、「クローン」などといった用語で説明されています。
もし必要になった際には、これらのワードで検索を掛けてみてください。