2007年05月18日 14:15 [Edit]

この記事をクリップ! newsing it! Buzzurlにブックマーク b.hatena.ne.jp/entry javascript - 関数をtraceする

amachangのコメントを受けて追記
JavaScript: 関数の追跡 - 文系大学的IT系の悲哀からのTBを受けて追記

書き換えめんどいー。

IT戦記 - JavaScript の関数を「引数そのまま返す化」

alertだけ

alert(hoge);
hoge.method();
改行めんどいー。

alert + そのまま返す化

alert.s(hoge).method(); // 1 ステートのまま

Functionオブジェクトを拡張

というわけで、関数をtraceするmethodをFunction Objectに追加してみる。

まずは実例。

実装はこう。

Function.prototype.trace = function(name, tracer){
    var self = this;
    if (!name)   name   = this.name || '__ANON__';
    if (!tracer) tracer = function(n, a, r){
        alert( n + '(' + a.join(', ') + ') = ' + r);
    };
    return function(){
        var retval;
        try{
            retval = self.apply(this, arguments);
        }catch(e){
            retval = e;
        }
        var a = [];
        for (var i = 0, l = arguments.length; i < l; i++){
            a[i] = arguments[i]
        }
        tracer(name, a, retval);
        return retval;
    }
}

これなら何でもtraceできる。しかし関数名をtraceの引数に入れないといけないというのが面倒(その代わり、無名関数でもtraceできる)。

trace()を関数として実装

以下はFunction Objectを拡張するのではなく、通常の関数としてtrace()を実装した例。

function trace(name, obj, tracer){
    if(!obj) obj = window;
    if(!(name in obj)){
        throw new Error("No '" + name + "' method in object " + obj);
    }
    if (!tracer) tracer = function(n, a, r){
        alert( n + '(' + a.join(', ') + ') = ' + r);
    };
    var orig = obj[name];
    obj[name] = function(){
        var retval;
        try{
            retval = orig.apply(this, arguments);
        }catch(e){
            retval = e;
        }
        var a = [];
        for (var i = 0, l = arguments.length; i < l; i++){
            a[i] = arguments[i]
        }
        tracer(name, a, retval);
        return retval;
    };
}

使い方は、こう。

function mul(x,y){ return x * y }
trace('mul');
mul(2, 4);

ただし、見ての通り関数名を文字列として渡してあるので、無名関数には使えないし、レキシカル関数にも使いにくい。例えば、以下はエラー。

(funcition(){
    function mul(x,y){ return x * y }
    trace('mul');
    mul(2, 4);
})();

こうすれば動く。

(funcition(){
    var o = {};
    o.mul = function(x,y){ return x * y };
    trace('mul', o);
    o.mul(2, 4);
})();

まとめ

DRYさは損なわれるが、Function.prototype.trace()の方がJavaScriptっぽいように思う。

Enjoy!

Dan the JavaScripter

追記:

Function#nameはstandardではないとのこと。

Core JavaScript 1.5 Reference:Global Objects:Function - MDC
name: The name of the function (not part of the standard).

それでも、上記のように書き換えてもsafeなのでそうしましました。

追^2記:

JavaScript: 関数の追跡 - 文系大学的IT系の悲哀
ただ、Function.prototype.traceの中の10行目で、
retval = self.apply(null, arguments);
と、やってしまっているので、オブジェクトのメソッドをtraceしようとするとうまくいきません。

というわけで、nullをthisに変更しました。今度はうまく行くはずです。


この記事へのトラックバックURL

この記事へのソーシャルブックマーク
はてなブックマーク
Livedoorクリップ
0 Buzzurl
この記事へのトラックバック
IT戦記: JavaScript の関数を「引数そのまま返す化」404 Blog Not Found: 関数をtraceする この二つのブログには本当にお世話になっているんだが、相変わらずすごい。っていうか、よくこんなおもしろいことを思いつくなあ。
関数のトレース【文系大学的IT系の悲哀】at 2007年05月19日 00:39
http://d.hatena.ne.jp/amachang/20070517/1179427742 http://blog.livedoor.jp/dankogai/archives/50833481.html とかスマートだなあと思いつつ。 昔なんかやったよなあとか思ったらあった。 Kumuでコメントアウトにしてる部分だね。 元々AOPみたいなの作ってたんだな。 抜
[Kumu]関数のtrace【回転と脱線】at 2007年05月29日 14:12
この記事へのコメント
おお!先にやられた!

try { } catch(e) { } でエラーも trace 出来るとかなり実用的。
あと、 name は省略可能で this.name (関数の name プロパティ)から取ったらよりカッコいいかも。

と思いました!
Posted by amachang at 2007年05月18日 15:16
弾先生。
腐りきった、この世界に、一発どでかいゲームを打ち込んでみませんか!!
↓私のブログとメールアドレスです。気になったら、いつでも連絡下さい!!
http://d.hatena.ne.jp/mgcc/
moegi3212000@yahoo.co.jp
( ´∀`)σ)´Д`)プニュ
Posted by 大勲位モーリス・G・茶茶 at 2007年05月18日 18:20
ナルホド(^ω^)
Posted by 劇ちん at 2007年05月19日 15:45