日本昔話調のタイトルで始まりましたが、全く意味がありません、すみません。ごろどくですどうも。
今日は「オブジェクト(かObjectかobject)」についていろいろ調べてみたのでその辺をメモっておきます。
Objectとobjectとオブジェクト
前回のおさらい。
function abc (){}
console.log(typeof(abc.prototype));//object
var pqr = new abc;
console.log(typeof(pqr.prototype));//undefined
var xyz = {};
console.log(typeof(xyz.prototype));//undefined
function型オブジェクトを定義すると、セットした覚えのないprototypeプロパティが勝手に作られる(そしてそのデータ型はobject型)。object型オブジェクトにはそんなものは勝手に作られない、ということだった。
そしてもう一つ。
function abc(){};
console.log(typeof(abc));//function
var xyz = new abc;
console.log(typeof(xyz));//object
関数はfunction型オブジェクトだが、関数を元にnew演算子で生成されたオブジェクトのデータ型はobject型だった。また、このとき元となった関数のことを一旦「コンストラクタ関数」と呼ぼう。
世間的には単に「コンストラクタ」と呼ばれるが、ここではあえて「~関数」と呼んでおく。
なぜかは次の例を見てほしい。
console.log(typeof(Object));//function
「Objectオブジェクト」という表現がある。正しい。「JavaScriptのオブジェクトは全てObjectオブジェクトをプロトタイプとして作られている」とかね。
だが上のコードからわかるようにObjectオブジェクトのデータ型はfunction型だ。object型ではない。Objectが関数だとしたらもしかして「アイツ」がいるんじゃ?
console.log(typeof(Object.prototype));//object
いた。やっぱりいた。コードは省略するがArrayでも同じだ。そして空のオブジェクトを生成するサンプルとしてよく見るこれだ。
var abc = new Object;
typeofで調べてみるといい、
console.log(typeof(Object.prototype));//object
var abc = new Object;
console.log(typeof(abc.prototype));//undefined
これは冒頭の例と全く同じ構図だ。function型オブジェクトをnewするとObject型オブジェクトが生成されるのだ。
こう言い換えることもできるだろう。「newの仕事はfunction型オブジェクトをなぞって、同じような性質(プロパティ)や機能(メソッド)をもつobject型オブジェクトを生成すること」と。
「function型オブジェクトを」というのがミソだ。newは既存のobject型オブジェクトに対しては使用できない(というのはご存じだとは思うが)。何気なくやっているが
var abc = new Object//「Object」はfunction型オブジェクトなのでエラーは吐かない
//そしてabcはFunction型オブジェクトであるObjectオブジェクトをnewして生成されたonject型オブジェクト
var xyz = new abc;//「abcは関数じゃねぇよゴラァッ」って怒られる
ということだ。
そして「~なぞって、同じような性質(プロパティ)や機能(メソッド)を~」というのが、関数(function型オブジェクト)だけがprototypeプロパティを持つ(というか自動的に持たされる)ことと密接に関係しているはずだ。
それにしてもややこしい。(標準ビルトインの)Object(関数)と、(データ型としての)objectと、(一般的な)オブジェクト。これらはまったく意味が違う。
そしてここにたどり着くまでにいろんな参考記事読んだけど、明瞭に区別しないで書いてるものもあったりするから混乱するなあ。識者の頭の中では区別されてるんだろうけども。
プロトタイプ?prototype?
私だけかもしれないが、よく見かける表現で誤解してしまいそうなものとしてこういうものもある。
『JavaScriptの全てのデータはObjectに由来するオブジェクトで、どんなオブジェクトも全てプロトタイプを持つ』
このフレーズ自体は間違いではないだろう。が、もうちょっと違う言い方ができるはずだ。こういうのはどうだ。
『Javascriptのどんなオブジェクト(プリミティブ、オブジェクト、関数)も別のオブジェクトを原型として作られ、原型の原型の原型…を追っていくと最終的にObject.prototypeプロパティにたどり着く』
ちなみに私は最初のフレーズをあまり理解せずに次のように考えていた。
『JavaScriptのオブジェクトは全てprototypeプロパティを持つ』
ブッブー、残念。まったく違う。prototypeプロパティを持たないオブジェクトはある。先の例で見たようにobject型オブジェクトにはprototypeプロパティは存在しないね。少なくとも自動的に作られることはない。
var a = 1;
var b = '文字列だよ';
var c = true;
console.log(typeof(a.prototype));//unidentified
console.log(typeof(b.prototype));//unidentified
console.log(typeof(c.prototype));//unidentified
それはプリミティブなオブジェクトとて同様だ。prototypeプロパティを持てるのはあくまで関数(function型オブジェクト)だけ。
というところまで見えたのでここまで使ってきた「コンストラクタ関数」という呼称はやめて単に「コンストラクタ」と呼ぼう。
それと「コンストラクタを元にnew演算子で生成されたobject型オブジェクト」というのも長いので「インスタンス」と呼ぶことにする。
ちなみにこのインスタンスという語、Javaのようなクラスベースの言語のニュアンスで「クラス(実態を持たないひな形の定義)とインスタンス(クラスから生成された実態を持つオブジェクト)」といった文脈でJavaScriptについても解説しているテキストをネットでもしばしば見かけるが、JavaScriptではクラス-インスタンスの概念はないからね。
なぜなら先にも言った通り、JavaScriptのすべてのデータはObjectオブジェクトから派生したオブジェクトだから。関数(function型オブジェクト)でさえ例外ではない。だからコンストラクタも実態を持ったオブジェクトなんだ。
英語の「instance」は「例」を意味するそうだ。だからJavaScriptにおいては
- コンストラクタは「性質や振る舞いを定義したオブジェクト」
- インスタンスは「コンストラクタを動作できるようにした実例としてのオブジェクト」
って考えることにしようそうしよう銚子港揚子江。
JavaScriptに関する文献をネットで調べてて「クラス」なる語、あるいはそれを伴う文脈で出てくるインスタンスという語が出てきたらあなたにできることはただ一つ、「ブラウザそっとじ」だ。
さてこのままprototypeプロパティの話に突入したいが、そのためにはたぶん若干でもthisのこととかにも触れなきゃいけないっぽい。長くなりそうなのでいったん〆よう。あいかわらず次はいつ書くかわからないよ。んじゃまたー。
コメント