仮引数とクロージャ2007年05月04日 02時58分41秒

(元記事:あるSEのつぶやき: prototype.jsでプライベートメソッドを持つクラスを作る方法

ローカル変数の代わりに

個人的には最近まったく使わなくなっていた「JavaScriptによるプライベートフィールドの隠蔽」だが、あるSEのつぶやきさんが取り上げていたので一言(でもないか)。

リンク先記事で、Animal#defineメソッド内の実装で、プライベートフィールドをわざわざ定義しているが、これって、defineメソッドの仮引数「_sex」を_getSexで囲っちゃっても同じなんだよね。

15:	define : function(_sex) {
16:		//プライベートフィールド
17://		var sex = _sex; // ←コメントアウト
18:
19:		//プライベートメソッド
20:		var _getSex = function() {
21:			return _sex;// ←変更。仮引数にアクセスできるし。
22:		}
23:
24:		//Privileged(特権)メソッド
25:		this.getSex = function (){
26:			return Animal.SEXTYPE[_getSex()];
27:		}
28:	}
仮引数も、関数内でvar宣言されたローカル変数も、このメソッド内の実行コンテキストにバインドされた変数オブジェクトのプロパティであることには変わりがないので、宣言するだけ冗長かと。

同じIdentifierの仮引数とローカル変数の関係を見るために以下のコードを検証してみた。

function test1() {
	var a;
	return "test1: " + a;
}

function test2(a) {
	return "test2: " + a;
}

function test3(a) {
	var a;
	return "test3: " + a;
}

alert( test1("hoge") ); // 'test1: undefined'
alert( test2("hoge") ); // 'test2: hoge'
alert( test3("hoge") ); // 'test3: hoge'
Firefox1.5でしか試していないが、たぶんどの処理系でも同じだと思う。ポイントはtest2とtest3の結果が同じになること。 ついでだが、test3内でローカル変数宣言に代入式を与えると、当然仮引数「a」はオーバーライドされるので、違う結果になる。

おまけ

この手の解説で、以前は「Effective JavaScript」というよいコンテンツがあったのだが、現在は公開されていない。非常に残念だ。

現在はアクセスしても404になるのでリンクはせず、当時のURLを掲載しておく。www.archive.orgなんかを利用するとまだ確認できるかも。

http://www.interq.or.jp/student/exeal/dss/ejs/index.html

EXEを作ってみた2007年05月04日 03時11分17秒

これはちょっと便利かも

ゆるゆるとJSDBを試しているが、本家のチュートリアル眺めてたら、「Standalone JSDB programs」という項があって、

c:\temp>pkzip program.zip main.js

c:\temp>copy /b jsdb.exe+file.zip program.exe
c:\temp>program.exe
とか書いてあるじゃないですか。

さらに-helpオプションつけて起動してみたら、.zipのアーカイブをパラメータに渡せるとあった。

D:\jsdb>jsdb -help
JSDB 1.52Compiled Apr 27 2007.  http://www.jsdb.org/
Copyright 2003-2006 by Shanti Rao and others.

JSDB [-strict] [-werror] [-load file.js] [-debug server] [lib.zip] [program.js]

  -strict             Strict syntax mode
  -werror             Treat warnings as errors
  -load file.js       Load and run file.js before program.js
  -debug server:port  Connect to a debugger server
lib.zip Set lib.zip as the default location for library files Executes main.js if found in the zip file
program.js Runs a JavaScript program. If omitted, enter console mode D:\jsdb>
ということは、「main.js」にメインコードを記述し、それをzipで固めて、チュートリアルにあるように結合コピーするとオリジナルのコンソールアプリケーションが作れるってことじゃない!こいつぁ便利かも。

早速試してみた

まず、以下のコードを「main.js」で保存。コードの中身はかなり適当。

write("what your name ? > ");
writeln( "hello, ", readln()," !!" );
sleep( 1000 );

そんで、main.jsをmain.zipとして固める。

そしてチュートリアルにある要領で、コピー。hello.exeとした。

D:\jsdb>copy /b jsdb.exe+main.zip hello.exe
jsdb.exe
main.zip
        1 個のファイルをコピーしました。

D:\jsdb>
さて、hello.exeを実行。
D:\jsdb>hello
what your name ? > hoge
hello, hoge !!

D:\jsdb>
おお、ちゃんとできてるよ。

使い道

とりあえず思いつくのは、ライブラリ読み込み処理をmain.jsに記述してカスタマイズした実行環境にするってとこかな。

と思ったが、アーカイブ内のmain.jsを実行するとそのまま終了しちゃうので、この方法だとドラッグドロップ専用になっちゃうな(たぶんコマンドライン引数は受け取れるだろうから)。 もっとも、ライブラリロードを起動時になんとかするんだったら、-loadをくっつけたバッチファイルにしちゃえばよいんだし。ちぇ。