Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

JavaScriptとオブジェクトの関係

JavaScriptのオブジェクトと、関数の関係性

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2007/10/05 14:00

JavaScriptは少しクセがある言語ですが、一度分かってしまえば非常に便利で、さまざまな場面で活用することができます。本稿では、JavaScriptを理解するにあたり、つまづきやすいところにフォーカスを当てて解説していきます。

はじめに

 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と他の言語での大きな違いといえるでしょう。この関数オブジェクトは、「代入が可能」というオブジェクトの性質と、「実行時の動きを定義する」というクラスや型定義のような2つの要素を持っています。C言語が分かる人は、関数ポインタのようなものだと理解すれば良いと思います。

関数の中に関数を入れる

 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演算子の組み合わせです。このパターンを最初に見たときは、少し違和感を感じるかもしれません。

関数オブジェクトと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はオブジェクトの使い方や、オブジェクトと関数の関係性を知ることで、理解を深めることができます。

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 飯塚 友裕(イイヅカ トモヒロ)

    Eclipse関連のソースコード自動生成プロダクトの開発者。 ソースコード自動生成エンジンを他社に供給する技術エンジン会社「CROSSFIRE JAPAN, INC.」で、O/RマッピングツールやJavaによるSQLパーサーを開発。 現在、NetBeans.org(米国)のパートナー。 最近は...

All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5