2014年7月28日

javascript 引数の無名関数内のみで使える関数

Jaml などのHTML ジェネレータを調べてる際に気付いたことだが、javascript では、引数に渡す無名関数内のみに関数を公開する方法がある。

[Jaml のサンプルコード]

Jaml.register('sample', function(){
    div(
        h1('サンプル'),
        p('Jaml です。'),
        br()
    );
});

上記サンプルの無名関数内で呼び出している div や h1 などの関数は、外部に公開されていない(グローバル関数ではない)。
どうやって実現しているのかさっぱり分からなかったので、Jaml のソースを拝見。
div や h1 は Jaml.Template の prototype 関数で、with と eval で実現できる模様。

[実現コード]

//[定義]
var Test = {
    console : function(callback){
        var logger = new Logger();
        //・callback を文字列展開して eval 実行することで、
        //  callback の変数スコープをこの関数内に変更
        //・with を使って prototype 関数に直接アクセス
        with( logger ) eval('(' + callback.toString() + ').call(logger)');
    }
};
var Logger = function(){ this.count = 0; };
Logger.prototype = {
    log: function(message){
        console.log(message);
        this.count++;
    },
};

//[実行]
Test.console(function(){
    log('one');
    log('two');
    log(count);
});

//[結果]
// one
// two
// 2

prototype 関数でなければ with で囲む必要はない。
上記例で、Test.console 内に定義した関数なら、外部に公開されず、引数の callback 内でのみ使える関数となる。

おまけ

本題とはあんまり関係ないけど、Jaml から eval と with を除いたもの。
Jaml.register に渡す無名関数の第一引数に Jaml.Template インスタンスが渡されるので、そこから div や h1 などのメソッドを使う。

0 件のコメント:

コメントを投稿