Warning: The magic method InvisibleReCaptcha\MchLib\Plugin\MchBasePublicPlugin::__wakeup() must have public visibility in /home/c9138697/public_html/juncleit.com/wp-content/plugins/invisible-recaptcha/includes/plugin/MchBasePublicPlugin.php on line 37
JavaScriptの勉強中にクラスとインスタンスを語る | マサトッシュブログ

JavaScriptの勉強中にクラスとインスタンスを語る

JavaScript

いつもは一旦下書きしてから記事をアップしているが、今回は書き殴りしてみる。

今JavaScriptで少し簡単なDBアクセスツールを作ろうとしてJavaScript言語自体を勉強している。そこで少し疑問に思ったことがあったので下書きなしで描いてみようと思う。

Promiseという「オブジェクト」

JavaScriptの非同期処理をうまく扱うオブジェクトとして「Promise」というオブジェクトが「ビルトインオブジェクト」として定義されている。これを再度理解しようと思って記事を読み漁っていたのだが、そこで出てきた言葉「オブジェクト」が気になった。

私はもともとJava使いであり、あまりプログラム言語の1要素として「オブジェクト」という曖昧な言葉を使わない。Javaでは「クラス」と「インスタンス」という言葉を頻繁に使うし、「オブジェクト」という言葉は言語を語るよりも、むしろ設計時などに処理概要を表現する時に使うぐらいだと思う。

このような感覚を持っている私がJavaScript勉強中に出会った「Promiseというビルトインオブジェクト」もしくは単に「Promiseオブジェクト」という言葉。私はどうしても「クラス」と置き換えてしまう。ということで、私の中で「Promiseオブジェクト」=「Promiseクラス」に変換しまくっている。

クラスとインスタンス

これはnew演算子を使ってProimseクラスを実行可能な状態にする事を意味しており、これはJavaでもJavaScriptでも同じ言葉を使用するようだ。


const promise = new Promise(executor);

「クラス」(JavaScriptではオブジェクト?)というのは、そのクラスで実行したい「プログラム」と、そのプログラムで使用する「データ」の格納方法を定義したテンプレートのようなモノで、クラスはそのままではプログラムとして実行できない。プログラムの実行方法を定義しただけである。

クラスにはデータだけ定義する事も、プログラムだけ定義することもできる。どちらも「クラス」に属するため、可読性が向上する(「xxクラスのxxというメソッド」とか「yyクラスのyyというデータ」など、クラス名を枕詞にするだけでどこにあるかが明確になりやすい)

さらにクラスに定義するプログラムやデータには「アクセス指定子」を付与することができる。これにより、そのプログラムやデータがどこからアクセスできるのかを限定する事ができる。これはプログラムの保守性が向上する。

「インスタンス」とは、クラスに定義された「プログラム」をメモリ上にロードし実行できるようにする事と、プログラムで使用する「データ」を格納するためのメモリを割り当てる事で、実行可能な状態にしたもの。

インスタンスは、1つのクラスから複数のインスタンスを生成することができる。この時、クラスに定義した「プログラム」は一度メモリにロードされると他のインスタンスからも再利用されるのが一般的で何個も同じプログラムがロードされることはない。一方で「データ」の格納領域はインスタンスごとに新たにメモリが割り当てられる。

「プログラム」が再利用されるのは1つのプロセスないの話であり、複数のプロセスで共有されることはない。ただし「1つのプロセスを複数のプロセスで共有する」という事もできるので、それはさらに別の扱いだったりする。

「データ」領域がインスタンス毎に割り当てられるというのは「static」定義されていない事が条件。static定義された変数は、1つのプロセス内で何度インスタンスを生成しても1度しかメモリ割り当てされない。複数インスタンスで共有される。

ちなみに、クラス定義のやり方次第では、1プロセスで1インスタンスしか生成できなくするように定義する方法もあり、このような制限をかける事で「わざと」単一インスタンスしか生成できないようにする必要のあるリソース(例えばファイルへの書き込みを行うクラスとか、複数箇所から同時にアクセスすると不整合が発生しそうなもの)を定義することもある。

Promiseは、new演算子でインスタンスを生成する時にexecutorという関数定義を受け取る。これはPromiseが内部で関数をデータとして格納できる事を表現している。

インスタンス変数の役割とGC(ガーベッジコレクション)

new演算子の結果がpromise変数に格納されているが、この変数に何を格納しているかというと、new演算子によって生成されたPromiseクラスのインスタンスがどのメモリ領域に保存されているかを変数に保持している。

このように変数に対してインスタンスのメモリ領域へのベクトルを保持しておかないと、new演算子で生成したインスタンスへアクセスするための手段がなくなり、メモリの使い損となるわけである。

そしてインスタンスが格納されているメモリへのベクトルを保持した変数がなくなってどこからもアクセスできなくなった事を言語ランタイム環境が検出すると、その領域はGC(ガーベッジコレクションとといって、プログラムで使っていないメモリを探し出し、解放する役割を持つプロセス)によってお掃除されてしまう。これによりメモリを割り当てるというCPU負荷とメモリを解放するというCPU負荷が無駄に使用されてしまうのである。

ちなみに、GCは敵ではない。プログラムによって廃棄されたインスタンスが無駄に占有しているメモリを他の処理や別のプロセスで利用できるように解放してあげる味方である。GCがどのような仕組みで動いているのかは言語ランタイムにより異なるが、その仕組みや特徴を理解することはメモリ利用の効率化やパフォーマンスに大きく影響する可能性があるため重要である。

日本語訳って難しい

変数やGCなど、少し言語やランタイム的な話にも踏み込んで書いてみたが、いやはや、英語圏で定義されたものをわかりやすく日本語に訳すというのはとても大変な作業だと実感できる。

そもそも「インスタンス」とか「クラス」とか「変数」とか、説明を受けるとなんとなくわかるけど、たまにツッコミたくなるネーミングや日本語訳があったりすることも。「こういうもの」という感覚で無条件で覚えていかないと中々しんどいところがある。

今もそうだけど新しいオープンソースや製品で、同じような概念を表現する時に異なる言葉を使ってたりするし、それをそのまま日本語に訳すから、過去の知見を活用しにくい場面もある。

新しい事を勉強するときは、いかにより高い次元で俯瞰的にモノが見れるかといった力が必要だ。特にプログラム言語というものは、1つの言語を習得(プログラム言語仕様を理解し、作るものが決まっていれば、そのプログラム言語を使って、悩みながらも自分でガシガシ開発を進めることができる能力が身についた状態と定義してみた)すると、他の言語を勉強する時にはゼロベースではなく、6〜7割はサクッと理解できるだろうが、それは1つの言語を習得したことで、「プログラム言語ってこうだよね」的な、より高い見方ができるようになったためであると思われる。

新しい事を学ぶというのは楽しい

最後に、色々と書いたが、今はとにかく新しい言語を勉強している事自体が楽しい。そしてその言語を勉強しつつ何か物作りができること自体、最高に楽しい。プログラム言語を勉強する理由は、何かを作り出したいからであり、言語を習得することが目的にならないよう注意しなければならないといつも感じる。

コメント

タイトルとURLをコピーしました