はじめに
JavaScriptは、とても不思議で面白い言語です。ただ、特徴を掴みきるまでは難解だと思ってしまうと思います。今回は、JavaScriptを理解するコツをいくつか紹介しようと思います。
インタプリタだと思うからややこしい
JavaScriptでもっとも難解なのは、「今まで定義していないクラスであっても、あたかも定義されていたかのように、好きなタイミングでインスタンス(変数)を生成できる」という点です。
例えばJavaなどのコンパイラの場合は、実行する前に一度全てのソースをコンパイラが見渡すため、ソースコード全体からクラス定義を見つけ出してインスタンスと関連づけることができます。そのため、クラス定義の実装タイミングやソースコード上での位置がどこであっても問題になりません。
ところが、1行1行読み込みながら実行するイメージのあるインタプリタで、JavaScriptのような記法があると混乱を招いてしまいがちです。そのため本稿では、(実際には違うのですが)「JavaScriptはコンパイラ形式なんだ」と自分に嘘の暗示をかけて読み進めていただけると分かりやすくなるかと思います。
JavaScriptは関数もオブジェクト
JavaScriptでは関数もオブジェクトです。そのため、次のような記述をすることができます。
var sample = new Object(); //関数定義と代入 sample.func1 = function(str) { alert("Hello " + str); } //実行 sample.func1("World");
この記述では、sample.func1
という名前の関数が定義されます。そして、、この関数を実行しています。
このコードから分かることは、関数自体もオブジェクトだということです。function(str)
という、予約語「function」を使った記述方法で匿名の関数オブジェクトを作り、それを、sample
オブジェクトのfunc1
というプロパティに代入しています。代入後は、このfunc1
というプロパティを関数として使うことができるようになります。
この書き方は、JavaScriptでネームスペースのような働きをさせるのに便利です。筆者は、現在、JavaScriptのコードを自動生成させるようなプログラムを開発していますが、この機能のおかげで自動生成した関数の名前が衝突するのを避けることができるため、非常に重宝しています。
また、このJavaScriptで定義した関数をHTML内のイベントハンドラで指定するときには、次のような書き方が可能です。
<html> <script type="text/javascript" src = "test.js" charset = "utf-8"> </script> <body onload="sample.func1('World')"> </body> </html>
関数の中に関数を入れる
JavaScriptでは、関数の中に関数を入れることもできます。この機能は、ちょっとしたユーティリティ的な機能を関数として分離し、ソースコードの可読性を上げたいときなどに便利です。
var sample = new Object(); //関数定義 sample.func1 = function(str) { innerFunc(str); // 内部の関数定義 function innerFunc(obj) { alert("Hello " + obj); } return 0; }
ここで気を付けてもらいたいのが、innerFunc()
関数は、sample.func1
の内部で定義されていますが、代入されていないという点です。
最初に示した「関数オブジェクトの例」では、関数オブジェクトをプロパティに代入する前にプロパティを関数として呼び出すとエラーになります。しかし今回は、代入を行わなくても関数を呼び出している行より後に定義された関数を呼び出すことができます。
innerFunc()
関数は、sample.func1
の内部で自由に使うことができます。ただし、他の場所では使うことはできません。そのため、プライベートな関数を作りたいときには最適です。
関数とプロパティをあわせて使う
次は、プロパティの値をオブジェクトで保持し、それをオブジェクトの関数で増やしていくサンプルです。
var sample = new Object(); //プロパティ sample.i = 0; //関数定義 sample.func1 = function() { this.i++; alert(this.i); } //繰り返し呼ぶ sample.func1(); sample.func1(); sample.func1(); sample.func1();
このサンプルでは、最初に設定されたプロパティのi
が呼ばれるたびに1インクリメントされて、アラートダイアログで表示されます。この動きから、this
を使って、関数からオブジェクトのプロパティにアクセスするプログラミングが可能なことが分かります。
定義したオブジェクトをNewする
次のパターンでは、定義した関数とnew演算子の組み合わせです。このパターンを最初に見たときは、少し違和感を感じるかもしれません。
var sample = new Object(); //コンストラクタ関数定義 sample.func1 = function() { this.i = 0; this.method1 = function(){ alert("The Member function is called."); } return 0; } var newObj = new sample.func1(); //メソッドを呼ぶ newObj.method1();
この場合、new演算子で指定したfunc1()
関数はコンストラクタとして扱われます。コンストラクタは、オブジェクトをnewしたときに呼び出される関数です。具体的には、new演算子を使っている行でこのコンストラクタが呼び出され、そして、this
を使ってプロパティおよびメンバーの設定を行っています。
newObj
に渡されるオブジェクトは、コンストラクタの「this」が参照しているオブジェクトで、コンストラクタ内でセットしたメソッドを、newObj
を介して呼び出すことができます。
まとめ
以上のように、JavaScriptはオブジェクトの使い方や、オブジェクトと関数の関係性を知ることで、理解を深めることができます。