2007年02月15日

Javascipt:関数ごとに終了状態をトレースしてゆく関数

関数終了時の変数の状態や arguments などを順次蓄積します。関数内の変数は簡易的にスキャンして、一括取得できるようになっています。
前回の「Javascipt:関数が終了した後でもそのローカル変数が参照できる」を発展させて、関数に eval(getChain()); と記述するだけで、トレース出来るようにしたものです。

機能は以下になります。
  • arguments, caller, callee を保存
  • 終了時の変数の値を個別・一括で取得
  • 複数の関数の終了時の状態を起動順序ごとに配列へ蓄積
確認環境
ie 5.0, 5.5, 6.0, 7.0
ff 1.0, 1.5, 2.0
ns 7.1
※ opera は caller が無いため動作しません。
参考:http://www.opera.com/docs/specs/js/ecma/

注意点
対象とする関数が起動されるたびに延々と蓄積し続けます。
Array.shift() などを使って配列を詰めてもいいかも知れません。

■2009/04/24追記
変数を監視する場合はこちら
javascript:変数を監視する関数



  ソース

トレース用関数の本体
function getChain(){
  if(!getChain.data) getChain.data = [];
  var cle = arguments.callee.caller;
  var cnt = getChain.data.length;
  getChain.data[cnt] = {
    callee : cle,
    caller : cle.arguments.callee.caller,
    arguments : cle.arguments,
    getValue : void(0),
    getValues : function (){
      var vn = getValueName("" + cle), val = {}, tmp;
      for(var i = 0; vn.length > i; i++){
        tmp = getChain.data[cnt].getValue(vn[i]);
        if(typeof(tmp) != 'undefined') val[vn[i]] = tmp;
      }
      return val;
    }
  }
  return 'getChain.data[' + cnt + '].getValue = function (val){try{return eval(val);}catch(e){}}';
}

arguments 他は、呼び出し先からでも取得できますが、関数内の変数を参照する関数は、参照したい関数内で eval する必要があります。このため、eval 用の文字列を返します。

関数内の変数名を取得する関数
function getValueName(str){
  var vn = [];
  var i = str.match(/(var¥s)[^;]*⁄gi);
  if(!(i instanceof Array)) i = [];
  str = i.concat(str.match(/¥([^{}¥(]*¥)/gi)[0].replace('(', '').replace(')', ''));
  for(var i = 0; i < str.length; i++){
    str[i] = str[i].replace('var ', '').split(',');
    for(var t = 0; t < str[i].length; t++){
      str[i][t] = str[i][t].split('=');
      vn[vn.length] = str[i][t][0].replace(/^¥s+|¥s+$/g, "");
    }
  }
  return vn;
}

関数(ソースコード)から正規表現で変数名を取得する関数です。
var 〜 ;を見つけると、「,」で split、さらに「=」で split して変数名を取得します。引数は、コードの最初に現われる「()」内を検索します。おそらくこれで十分だと思いますが、精査してません。

正規表現でコードから引っ張るのは、まったくもってスマートじゃないのですが、Activation オブジェクトにはアクセスできないので他に方法は無いかなと思います。

  使い方

サンプルはこちら

トレース
トレースしたい幾つかの関数内のトップに以下を挿入します。
eval(getChain());

参照
配列 getChain.data[n] に関数の終了時の情報が蓄積されます。
n = 0; が最初です。
arguments の取得
getChain.data[n].arguments を参照します。
callee の取得
getChain.data[n].callee を参照します。
caller の取得
getChain.data[n].caller を参照します。
変数値の取得
ret = getChain.data[n].getValue('変数名');
ret に 変数の値が返されます。
変数値の取得(一括)
ret = getChain.data[n].getValues();
ret に {変数名1:変数値1, 変数名2:変数値2, ・・・}などの連想配列様のオブジェクトが返されます。

  雑感

やり始めたら面白くって作ってみましたが、徒労感が・・・。これってデバッグ以外に用途あるのか!?と思いつつも、認めたくなかった事実に襲われています。
タイトルに御幣があるかなぁ。簡潔に表現するのって難しい。


posted by HiFa at 10:59 | 🌁 | Comment(0) | TrackBack(1) | JavaScript雑感 | このブログの読者になる | 更新情報をチェックする
>>> スパムコメントは消してますよん。 お互い無駄な労力は避けましょう。 <<<

この記事へのコメント

コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

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

javascript:変数を監視する関数
Excerpt: こちらは変数を監視する関数です
Weblog: Script雑感
Tracked: 2009-04-24 13:37