WIZ-CODE.blog

JavaScriptやAjaxをテーマとしたブログです。

*

Prototype.js バージョン1.7公開に合わせ小技紹介その1

   

先月、有名なJavaScriptライブラリPrototype.js最新安定バージョンがリリースされました。ライブラリのシェアは明らかにjQueryその他に打ち負かされてはいるものの、まだまだ人気は根強く自分も愛用者の一人です。これまで腰を入れてPrototype.jsのコードを読んだことがないので、今回は一から念入りに読んで参考にしたいと思っています。 有名どころのライブラリのコードを見ると、速さ・簡略化のための技術がふんだんに取り入れられていてとても参考になります。たとえば、Prototype.jsではブラウザ判定が、Prototype.Browserというプロパティから参照できるようになっていますが、コードを見ると下のようになっています。ここではbrowser1という変数に変えてありますが、小かっこ()で囲まれた関数の実行結果(戻り値)を代入していることが分かります。最終的に各ブラウザのプロパティを持つオブジェクトが代入されます。この方法をとる利点は何でしょうか。
 
var browser1 = (function() {
	var ua = navigator.userAgent;
	var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
	return {
		IE:             !!window.attachEvent && !isOpera,
		Opera:          isOpera,
		WebKit:         ua.indexOf('AppleWebKit/') > -1,
		Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
		 MobileSafari:   /Apple.*Mobile/.test(ua)
	}
})();
 
//browser1はオブジェクトなのでそのままドットシンタックスでブラウザを指定すればいい。
alert( browser1.IE );
ひとつはグローバル名前空間を汚さないという点があります。クロージャというJavaScriptの特性を利用しています。これはよくつかわれるテクニックです。それでは、クロージャを使わないとどうなるか。下に示すように関数を使わない方法で同じようにブラウザ判定をしてみると……
 
var ua = navigator.userAgent;
var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
var browser2 = {
	IE:             !!window.attachEvent && !isOpera,
	Opera:          isOpera,
	WebKit:         ua.indexOf('AppleWebKit/') > -1,
	Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
	 MobileSafari:   /Apple.*Mobile/.test(ua)
};
 
alert( browser2.IE );
ブラウザ判定にbrowser2の他にua、isOperaというグローバル変数が使われているため、グローバル名前空間を汚染する可能性が高まってしまいます。JavaScriptではライブラリ同士の衝突がよく問題になるので重大なバグにつながる恐れがあります。 もうひとつの利点は、関数呼び出し時の処理を軽くするというのがあります。次の例を見てみます。これは単純に元のコードから()を取り去ったものです。
 
var browser3 = function() {
	var ua = navigator.userAgent;
	var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
	return {
		IE:             !!window.attachEvent && !isOpera,
		Opera:          isOpera,
		WebKit:         ua.indexOf('AppleWebKit/') > -1,
		Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
		 MobileSafari:   /Apple.*Mobile/.test(ua)
	}
};
 
//browser3はメソッドなので一度呼び出した上で、ドットシンタックスでブラウザを指定する必要がある。しかし、これだとブラウザを確認するたびにいちいちメソッドを呼び出すことになる。
alert( browser3().IE );
ブラウザ判定を関数(メソッド)にすると、内部でローカル変数を参照するのでグローバル名前空間の汚染は避けられるものの、ブラウザを調べたいときにいちいち関数を呼び出さなければならなくなります。こうしたことから、browser1のように関数を()でくくってその場で実行するのが、処理の速さと汚染対策を両立する最良の方法となるわけです。 しばらくPrototype.jsを読解しながらここで使われるテクノロジーの紹介を続けてみたいと思います。

 - JavaScript/Ajax, ブラウザ , ,