4月だし新人さんに知ってほしいなってのも含めて。
JavaScriptって値と関数とオブジェクトって型がある。何か似てるんだけど、これらの区別がちゃんと理解できるのとても大切。これらの区別ができないと変数と代入が半分も理解できない。いや、本当に。
初学者向けの説明ってかなり手抜きな説明されてるのが多すぎる。変数は入れ物です、って感じのやつ。
それでいながら、値または関数とオブジェクトでその入れ物の扱い方違いますよ、ってとこまで中々説明してくれない。
そういう説明がされていないから
var ar = [1, 2, 3];
var ray = [1, 2, 3];
console.log( ar === ray ); // trueだと期待するが実際はfalse
と、trueを期待しちゃう。
「何でtrueじゃないの?」
という疑問に
「arの参照してるオブジェクトとrayの参照しているオブジェクトは別ものだから」
って答えても、この意味が通じない。
脱初級ができない悶々としている人が一体何をわかっていないのかを観察すると大体これ。参照の概念がない。
この意味が通じるようにどうしたものか。
もうね、これは本当に前提知識だから明確に区別していくしかない。
値と関数とオブジェクトは別物
ってイメージを作り上げていくしかない。
その三つって何?ってとこから始めてみる。
値と関数とオブジェクト
まずは値から。
値
値って?こいつらのこと。
- 数値
- 文字列
- 論理値 (真偽値)
- undefined
具体例
1, '1', true, undefined
あと
Infinity, NaN
や、
Number(1), String('abc'), Boolean(true)
とかも。
関数(ファンクション)
関数ってのは
function square(number) {...}
こんな感じで書かれているやつ。
随分手抜きだが関数の詳しい話をし始めるとちょっと大変。だから詳細は https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Functions に任せる。
ここで話したいことは値と関数とオブジェクトは別物だよって話。だからそのイメージをまず持ってからMDNのドキュメントを見てくれればって思うので詳細の確認は後回しで結構。
関数の小難しい書き方は
new Function(...);
って書く。
オブジェクト
値と関数じゃないものがオブジェクト。何か身も蓋もないような説明なんだけど実際そういうもの。
区別を目的としているからこのイメージで今はいい。
具体例は、こいつら。
{}, []
んで、こいつらの小難しい書き方はこう。
new Object(), new Array()
関数に new
キーワードでオブジェクト生成。
だから
Number(1), String('abc'), Boolean(true)
は、値を返しているのだけど
new Number(1), new String('abc'), new Boolean(true)
で、これはオブジェクトになる。
あ、忘れそうだったけど
null
こいつもオブジェクト。
型を調べるコード
値なの?関数なの?オブジェクトなの?を調べるには
typeof 〜
って書く。型が何かを文字列で返してくれる。
typeof の戻り値 | 型の種類 |
---|---|
'number' | 値 |
'string' | 値 |
'boolean' | 値 |
'undefined' | 値 |
'function' | 関数 |
'object' | オブジェクト |
* 'xml'って戻り値もあるけどここでは扱わない。 |
typeof 1 === 'number';
typeof Number(1) === 'number';
typeof Infinity === 'number';
typeof NaN === 'number';
typeof '1' === 'string';
typeof String('abc') === 'string';
typeof true === 'boolean';
typeof Boolean(true) === 'boolean';
typeof undefined === 'undefined';
typeof function(){} === 'function';
typeof new Function() === 'function'
typeof {} === 'object';
typeof [] === 'object';
typeof null === 'object';
typeof new Object() === 'object';
typeof new Array() === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';
typeof new Boolean(true) === 'object';
これ全部 true になる。
オブジェクト型の詳細を調べる方法があるんだけどそれは今回はパス。か、後で書くかも。
これが値と関数とオブジェクトの区別。
変数
続いて値と関数とオブジェクトを代入する変数のお話。
変数とはウィキペディアを見てみると
プログラミングにおいて、変数とは、プログラムのソースコードにおいて、扱われるデータを一定期間記憶し必要なときに利用できるようにするために、データに固有の名前を与えたものである。 一人一人の人間が異なる名前によって区別されるように、一つ一つの変数も名前によって区別される。
らしい。
もう少しイメージしやすい説明がいいよね。なので考えてみた。
よくある変数の形。
var a = 1;
var b = function(){};
var c = {};
これのイメージはこんな感じ。
コードには書かれていないけど、型を意識してみるとこう。
更に参照の概念を持ってほしいので、変数名・値・型の他にアドレスを用意する。
アドレスも含めた一定期間記憶する領域を描いてみた。この領域っていわゆるメモリのことなんだけどね。
さっそく値を入れてみよう。
アドレスってこんな連番で並んでいないけど便宜上そういうものだと思ってて構わない。
値や関数・オブジェクトってメモリではこんな風にアドレスや型が意識されている。あくまでも風ね。概念の説明だから細かいことは気にせずに。
変数名はわざと記入しなかった。値と関数・オブジェクトでは振る舞いが違うのでそれを説明する為に空けておいた。
ではまず値が1の項目に変数名を割り当ててみる。ソースは
var a = 1;
var b = function(){};
var c = {};
こうだったから、イメージは
こんな風になっているはず。このイメージは正しい。
次は関数のfunction(){}のイメージを。
アドレス#002のところに変数名bのイメージ。 このイメージは間違い。
型が値であれば変数名がそこで正解なのだが、型は関数。
では関数の時はどういうイメージなのか?
こういうイメージ。
変数名 a には 1 という値が入っている
変数名 b には #002 というアドレス値が入っている
そして 変数c とオブジェクト {} のイメージは b と同様に
#003 というアドレス値が入っている。
このイメージを踏まえて次のソースを見てほしい。
var a = 1;
var b = function(){};
var c = {};
console.log(a); // => 1
console.log(b); // => function(){}
console.log(a) のケースは aの値である1そのもの を示している。変数aが扱っている型が値であるから。
console.log(b) のケースは bの値であるアドレス#002の値 を示している。このアドレスの値を示すことを 参照 というんだ。
もし console.log(c)
とあったら、それはアドレス#003の値 {} を示すことになる。
参照のイメージを掴めただろうか。
イメージが掴めていれば冒頭の ar === ray
が false なのも説明がつく。
var ar = [1, 2, 3];
var ray = [1, 2, 3];
console.log( ar === ray ); // false
これのイメージは、
こうなる。
そして ar === ray
の意味は #001 === #002 になる。arは アドレス#001の[1,2,3] を、rayは アドレス#002の[1,2,3] を示すことになるので、これらは別のものである、という解釈になる。故に ar === ray
は false なのだ。
では、
var ar = [1, 2, 3];
var ray = ar;
console.log( ar === ray );
これはどういう解釈となるか?
arに#001というアドレス値が代入されたとしよう。rayにはarのアドレス#001の値[1,2,3]が代入されるのではなく、オブジェクト型になるのでやはりそのアドレス値#001がrayに代入されることになる。そして ar === ray
は同じオブジェクトを示していると解釈されるので true となる。
何故、関数やオブジェクトは値のように代入せず、こんな回りくどいアドレス値を代入するのだろうか?ちゃんとその理由はある。
代入したくてもできないから。
そもそも関数とオブジェクトって値型の組み合わせの表現なんだ。
先ほどのイメージよりちょっぴり詳しいオブジェクト型のイメージ図も描いてみよう。わかりやすいのは配列オブジェクト。
var a = [1,2,3];
こんな具合。
オブジェクトは値の様に扱いたくても扱えない。だから参照という形で扱う。
これがプログラミングにおける参照って概念。
以上なんだけど。
型という意味での値と関数とオブジェクトの区別ができるようになっただろうか。
自分にはこれ以上簡単に説明できない。
これで参照という意味が理解できなくても、それは僕の伝達力の無さの責任で貴方の理解力の責任ではないことだけは言っておきたい。
今すぐわからなくてもいい。プログラミングにおいて参照という概念は必ずつきまとう。いつの日か理解できるようになる。
参照という概念が身に付いた時、間違いなくエンジニアとしての第一歩を踏み出せている。その時は胸を張って自信を持ってほしい。
最後にお願い。参照の概念を持っていない人に、このことを伝えてほしい。そして参照の概念を持って何でもいいからプログラミングの基本ドキュメントを読み返してほしい。理解が驚くほど深まるはず。参照って概念は本当にとても重要なものなんだ。