JavaScriptでインターセプト
JavaScriptでメソッド呼び出しをインターセプトしてみます。
実装
- 渡されたオブジェクトの関数のうち、regexにマッチする関数を「インターセプターを実行する関数」に置き換えます。
- インターセプターは関数で指定。
- 引数として、関数名、オブジェクト自身、オリジナルの関数、関数に渡された引数を受け取る。
- オリジナルのメソッドの実行は「インターセプター内でオリジナルの関数をapply()」でいいよね。
/** * インターセプターを適用する。 * @param {Object} target 適用対象のオブジェクト * @param {Regex} regex 適用する関数名の正規表現 * @param {Function} interceptor 適用するインターセプター */ function applyInterceptor( target, regex, interceptor ) { for ( var f in target ) { if ( typeof target[f] == "function" && regex.test( f ) ) { (function() { // f をローカル化するため関数で。 var x = f; var original = target[x]; target[x] = function( ) { // インターセプターを実行する関数に置き換える。 return interceptor( x, target, original, arguments ); } })(); } } }
使い方 & サンプル
var stdout = document.getElementById("stdout"); /**クラス*/ function Kitten( name ) { this.name = name; } Kitten.prototype = { meow: function() { stdout.innerHTML += "meow!<br/>"; }, setName: function(name) { this.name = name; }, getName: function() { return this.name; } } // オブジェクトを作成。 var mii = new Kitten("mii"); // ★インターセプターを適用。メソッド実行の前と後でメソッド名を表示する。 applyInterceptor( mii, /^.*$/, function( f, target, original, arguments ) { stdout.innerHTML += "start. " + f + "<br/>"; // メソッド呼び出し前 try { return original.apply( target, arguments ); // 元の関数を呼び出し、結果を返す。 } finally { stdout.innerHTML += "end. " + f + "<br/>"; // メソッド呼び出し後 } } ); // 実行。 mii.meow(); // 戻り値あり var name = mii.getName(); stdout.innerHTML += name + "<br/>"; // 引数あり mii.setName("kuro"); name = mii.getName(); stdout.innerHTML += name + "<br/>";
実行結果です。
start. meow meow! end. meow start. getName end. getName mii start. setName end. setName start. getName end. getName kuro