なんてタイトルにしたら良いのかまったくわからんw
とはいえ、最近のハッとした事例。
var arr1, arr2; arr1 = arr2 = []; for (var i = 0; i < 3; i++) { arr1[i] = 1; } arr1 = []; console.log(arr1.length); // 0 console.log(arr2.length); // 3
わかってる人にはなんてことないこのコード。
でも、いわゆる「プログラミング」初心者にはこう見える・・。
誤解してる例
// arr1, arr2 という変数を2つ用意し、空の配列をいれる var arr1, arr2; arr1 = arr2 = []; // arr1に値をいれる // 3回繰り返す for (var i = 0; i < 3; i++) { arr1[i] = 1; } // arr1を空の配列にする arr1 = []; console.log(arr1.length); // さっき空にしたから当然0 console.log(arr2.length); // arr2には何もしてないから0でしょ? え?3?!
なにを誤解してるのか
// arr1, arr2 という変数を2つ用意し、空の配列をいれる var arr1, arr2; arr1 = arr2 = [];
まずコレ。
正しくは、arr1, arr2 という変数を2つ用意し、"単一の"配列を参照する
// arr1に値をいれる // 3回繰り返す for (var i = 0; i < 3; i++) { arr1[i] = 1; }
コレも正しくは、arr1に値を入れているのではなく、
arr1が"参照している配列に"、値が格納される
// arr1を空の配列にする arr1 = [];
あとコレ。
正しくは、arr1の"参照先"を、新たな配列に向ける
console.log(arr2.length); // arr2には何もしてないから0でしょ? え?3?!
よって、arr2は以前3回ループした配列を参照してるので、3。
ちなみに
まあObjectでやっても同じ。
var obj1, obj2; obj1 = obj2 = {}; for (var i = 0; i < 3; i++) { obj1[i] = 1; } obj1 = {}; console.log(obj1); // {} console.log(obj2); // {0: 1, 1: 1, 2: 1}
というか配列はそもそもObject(型)なので。
その誤解してる理論でいくと
var str1, str2; str1 = str2 = 'str' str1 = null; console.log(str1); // null console.log(str2); // str
なぜstr2がnullにならないのか。
これはJavaScriptのデータ型によって挙動が違って、
- Number
- String
- Boolean
- Null
- Undefined
にはこの理論が当てはまらなくて、
- Object
にだけ、当てはまるから。
正確には、
- Number
- String
- Boolean
- Null
- Undefined
これらはプリミティブ値で、値が格納されるタイプ。
どっかで聞いた単語を充てるなら、イミュータブル。
- Object
こいつは値ではなく参照が格納されるタイプ。
どっかで聞いた単語を充てるなら、ミュータブル。
プリミティブ値でイミュータブルなので
var str1, str2; str1 = str2 = 'str'; // str1 に 'str'、str2 にも 'str' を格納 str1 = null; console.log(str1); // null console.log(str2); // str2は最初に'str'を代入してから何もしてないので、 'str'
うーん、初心者的にはそんなこと言われてもまったくピンとこないシリーズよねー。
そもそも個人的にも、これをちゃんと言葉で説明するとどうなるのか、よくわかってないんですよねー・・。
プリミティブとかイミュータブルとか、そもそもそれがわかりにくいというかなんというか。
Objectのソレを参照渡しって言えるっぽいけど、果たして本当の”参照渡し”なのだろうかと考えだすともうね!