今日のコード
問題1 ふつうの値の場合
問題1
let a = 1;
let b = a;
a = 100; // 後からaにだけ100を代入し直す。
console.log(b); // さてbには何が入っているでしょう。 1? 100?
さて、これで出力される値は、どちらでしょうか?
正解は…
答え1
1
正解は、1ですね。これはまぁ、当然かと思います。
bにaが代入された時点で、b=1という、値が代入されているので、その後aに違う値が代入されても、bはそのまま1です。
問題2 オブジェクトの場合
問題2
let obj1 = {'one':'あ'};
let obj2 = obj1;
obj1.one = 'い'; // 後からobj1にだけ「い」を代入し直す。
console.log(obj2); // さてこれは? 「あ」? 「い」?
これはどうか。
答え2
{one: "い"}
こちらでは、なんと再代入していない方(再代入前にコピーされたもう一方)も、値が「い」になってしまいました。
問題3 配列の場合
問題3
let arr1 = [1,2,3];
let arr2 = arr1;
arr1[0] = 10000; // 後からarr1にだけ10000を代入し直す。
console.log(arr2[0]); // さてこれは? 1? 100?
こちらはどうか。
答え3
10000
はい。オブジェクトの場合と同様に、再代入していない方(再代入前にコピーされたもう一方)にも、影響がありました。
以下で詳しく説明します。
どういうことか
これは、JavaScriptのコピー(値を渡す挙動)における仕様によるものです。
JavaScriptでは、配列やオブジェクトがコピーされた場合(値が渡された場合)、基本的に参照渡しで渡される。
つまり、新しいarr2やobj2が作られて、新たに値が入れられるわけではない。
実は内部的には、arr2はarr1と同じものを常に参照しているだけ、(obj2はobj1を常に参照しているだけ)という状態になっている。
これにより、コピー元を変更すると、コピー先も影響を受けてしまうので、注意が必要です。
コピーしたい場合は、使い勝手が良いと噂のlodashの「_.deepClone関数」などを使うようにしましょう。