JavaScript
JavaScriptのクラスと関数は同じものなのか
もともとJavaScriptはクラスベースではなくプロトタイプベースのオブジェクト指向型言語として生まれている。
なので「オブジェクトの雛形」のようなものは本来無く、空のオブジェクト(正確にはプロトタイプオブジェクト)とコンストラクタを組み合わせる感じでインスタンスを生成する。(「インスタンス」という呼び方もクラスベース特有のものではあるが)
クラスっぽいものを書く時は、コンストラクタ代わりの関数を書き、その中でデータとメソッドを動的に生成して新オブジェクトのプロパティに追加していくという書き方をする。
- 関数をnewすると空のオブジェクトが生成され、関数内のthisはその空オブジェクトを指すようになる。
- その空オブジェクトに関数のプロトタイプが継承される。
- 関数はその空オブジェクトのコンストラクタとなり、それが呼ばれて実行される。
- 空オブジェクトへ次々にプロパティが登録されていき、インスタンスができあがる。
ざっとこんな感じでJavaScriptのnewは動いているらしい。
クラスベースのオブジェクト指向型言語とは全然違う動きだ。
この動作を考えると分かるとおり、インスタンスを量産するとデータはもちろんメソッドまでも量産されてしまう。
それではさすがにメモリがもったいないということで、メソッドはオリジナルの関数のプロトタイプに格納しておき、データのみ量産するという方法が一般的だ。
プロトタイプというのはJavaScriptでオブジェクトが他のものから機能を継承するための仕組みだ。
ここに格納された機能は、new命令で生成される空のオブジェクトに継承される。
継承は複製ではないので、メモリを圧迫しない。
つまりインスタンスを量産しても、メソッドは共有される。
ES6から、JavaScriptにもclass構文が導入され、クラスベース言語のような記述で書けるようになった。
しかし「書けるようになった」というだけで、JavaScriptがクラスベースの言語になったわけではない。
従来の書き方をクラスベース言語のように書けるようにしたシンタックスシュガーであり、中身は同じ動作をしているようだ。
とはいえ、他のクラスベースオブジェクト指向型言語と同じような記述ができるというのは読みやすくなるのでありがたい。
細かいことを言うと、function構文とまったく同じというわけではなく、class構文で書いたときはその中身が "use strict" したときと同じになる。(コードの先頭で "use strict" していなくても)
例えばメソッド中でthisにアクセスするコールバック関数を書き、それを他の関数に投げた時にthisがグローバルオブジェクトにならずundefinedになる。(ただしコールバック関数をfunciton()で書いた時だけ。アロー関数式で書いた時は問題ない)
「まったく同じことをシンタックスシュガーで書ける」というわけではない点は一応留意しておいたほうが良いかもしれない。
|