ボトルネックになってそうなインスタンスメソッドの実行時間を計測したかったので、Functionを拡張する方法をやってみた。
Function.prototype.bench = function(msg) { var self = this; var bind = (arguments.length >= 2) ? arguments[1] : null; return function() { var start; var res; var end; if (bind) { start = new Date().getTime(); res = self.apply(bind, arguments); end = new Date().getTime(); } else { start = new Date().getTime(); res = self.apply(this, arguments); end = new Date().getTime(); } console.log(msg + ": " + String(end - start) + "ms"); return res; }; }
こうやって使う。
var Person = function(name) { this.name = name; } Person.prototype.loopName = function(num) { var buf = []; for (var i=0; i < num; i++) { buf[i] = this.name; } return buf.join(""); } var p = new Person("せんとくん"); p.loopName = p.loopName.bench("せんとくん", p); //メソッドの差し替え var result = p.loopName(10000); //せんとくん: 7ms
console.log()のところを、自前のロガークラスなどにしたら、Firefoxじゃなくても測れますね。
参考にした記事の方法を、ほとんどそのまま使ってます。
こういうアプローチは面白いっすねーっていう話を職場の人にしてたら、「それって要するにAOPだよね」と言われた。
そうなのかー。
AOPってのは、Javaでは割と良くやることらしい。
Javaは1.4でStruts使ってた頃までしか知らないから、全然分からないや。AOPという概念を学ぶのにもう1回、Javaを触ってみるのが良いかも。
もともと堅い言語っていうか、横着できない言語が好きなんですよ。来年はJavaかPythonを触ってみたい。
Function.prototype.bench = function(msg) { var self = this; var bind = (arguments.length >= 2) ? arguments[1] : null; return function() { var start = new Date().getTime(); var res = self.apply(bind, arguments); var end = new Date().getTime(); console.log(msg + ": " + String(end - start) + "ms"); return res; }; }
apply関数の第一引数にnullを設定するとグローバルオブジェクト(IEであればwindowオブジェクト)のthisと同等になるみたいです。これは知らなかった。
最近のツッコミ
参号館 日記(ariyasacca)
いちいち前後にコード入れなくてすむからいいよね。<br><br>ところでコードの bind は計測前に差し替えると if/else の重複した処理がなくなって綺麗になると思います。<br><br>if (!bind) { bind = this; }
おー、なるほどなるほど!<br>しかしbindという名前の変数にthisが入っててapplyに渡すって、何だか変な感じw
というかアレか、thisじゃなくてnull渡せば、そのままwindowスコープで実行されるのか。知らなかったぜ!
すっきり!