2006年06月21日

JavaScript

今更の感も強いが、これまで見様見真似でしか書いたことのなかったJavaScriptを勉強した。

教科書はO'reillyの JavaScript: The Definitive Guide, 4th Edition, David Flanagan。 日本語訳は第3版がJavaScript第3版として出ているが、第4版は出ていないようだ。

web上のJavaScriptの紹介にはHTML上の効果としての使い方しか載せていないもの、入門と銘打っていても言語の表層的なシンタックスしか解説していないものがほとんどで、言語として理解しようとすると物足りない。

一方、この本では前半分を使って言語としてのJavaScriptを丁寧に説明している。特に他のプログラミング言語の知識がある人には非常にわかりやすく、面白い。後半はJavaScriptの主な用途であるウェブブラウザでHTMLと組み合わせての使用のため、そこで登場するJavaScriptオブジェクトを説明するとともに、合わせて必要となるHTMLフォームやCSS、クッキー等の知識も要領よく解説している。

言語としてのJavaScriptは結構面白く、一読してもっと早くこの本を読んでおけばよかったと感じた。ただ、多くの項目でブラウザやJavaScriptのバージョンによって色々事情が異なるらしく、互換性についての記述が細かい。そのため言語を使おうとする側としては面倒な感を受けるが、多様なブラウザが使われている現状では致し方ないだろう。もっとも、記述があることは解説書としてそういった差異を丁寧にフォローしていると言える。

そのJavaScriptという言語であるが、JavaScriptは演算子や制御構文といった基本的なシンタックスはCやJavaに似ている。コメントの構文もC/Java譲り。 しかし、似ているのはそれだけ。言語としてはむしろScheme等に近く、そこにプロトタイプベースのオブジェクトを持ち込んだ感じである。

まず、変数には型がない。値は数値(整数と浮動小数点数の区別はなく、64bit浮動小数点数で全てまかなう)、ブーリアン、文字列、そしてオブジェクトのみ。文字列はimmutable。これらの間で必要に応じて暗黙の型変換があり、便利でもあるが嫌らしいような気もする。

クロージャがある(クロージャはオブジェクトの特殊なサブタイプとして扱われる)。 関数定義はクロージャの変数への束縛にすぎない。次の2つはほぼ同義。

function foo(x) { return x }
var foo = function(x) { return x }

括弧をつけてfoo(1)とすれば関数適用だが、fooと名前だけ書くと変数として参照する。

クロージャであるから当然次のようなコードも可能。

function make_counter() {
  var x=0
  return function() { return x++; }
}
var c = make_counter()
alert(c()) // 0を表示
alert(c()) // 1を表示

以上に加えて、オブジェクトがある。JavaScriptでいうところのオブジェクトは畢竟、文字列をキーとする連想配列だ。オブジェクトの要素をプロパティといい、通常obj.propとして参照するが、obj["prop"]としても参照できる。連想配列なので、他の言語のハッシュテーブルにも似た

var p = { x: 10, y: 20 }

というリテラル表現でも書けてしまう。

オブジェクトのメソッドは、単にプロパティにクロージャが代入されているものだ。

obj.method = function () { ... }

後ろに関数適用の括弧をつけてobj.method()とすればメソッド呼び出しとなる。 ただし、JavaScriptの関数ではthisという暗黙的に用意される参照があり、obj.method()という形式で呼ぶとその関数の中でthisがレシーバobjを指す。ちなみに通常の関数呼び出しでもthisはあり、グローバル環境の実行コンテクストを指す。

オブジェクトの作成はnew演算子をつけて関数を呼ぶことで行う。new Constructor()とすると、新しい空のオブジェクトが作成され、関数Constructorが呼ばれる。関数Constructorの中ではそれをthisとして参照できる。オブジェクトを作るための関数(これをコンストラクタと呼ぶ)は、この新しいオブジェクトに必要なプロパティやメソッドを与えることでオブジェクトを「作る」。例えばこんな具合。

function Point(x,y) { this.x = x; this.y = y }
var p = new Point(10,20)

JavaScriptにはクラスという概念はないが、あるコンストラクタが作成するオブジェクトに共通のプロパティを集めたオブジェクト(これをプロトタイプと呼ぶ)を持てる。オブジェクトは、プロトタイプが持つプロパティを自分自身が備えているかのように振舞う。

function Circle(r) { this.r = r }
    // コンストラクタのprototypeプロパティがプロトタイプを指す。
    // デフォルトではプロトタイプは空のオブジェクト。
    // そこにメソッドを追加する。
Circle.prototype.area = function() { return 3.141592 * this.r * this.r }
var c = new Circle(5)
alert(c.area()) // 78.5398と表示

他にもあるが、JavaScriptはどういう言語かというと概略こんな感じの言語である。

追記。JavaScript: The Definitive Guideは2006年8月に5th editionが出版される予定らしい。5年振りの改訂で、XMLやAjax関連の記述も加筆されるようだ。