function style2prop(str) { return str.replace(/-[a-z]/g, function(str) { return str.charAt(1).toUpperCase(); }); }「無名関数ってこういうところに使うんですね」と太郎君が感心していると、そこにちょうど通りかかったのが、Javascriptの実行効率に関してものすごくうるさいことで知られる三郎君。「なになに?見せて」という三郎君に、コードを見せると、
「これ、実行効率上少しオーバーヘッドがあるよね。内部関数を隠蔽したいならもっと良い方法があるよ」と言います。
Life is beautiful: Javascriptクイズ(中級者向け):無名関数と実行効率の話
いくつか試してみた。
function style2prop(str){ return str.replace(/-[a-z]/g, function(str) { return str.charAt(1).toUpperCase(); }); } function style2prop2(str){ return str.replace(/-[a-z]/g, f); function f(s){ return s.charAt(1).toUpperCase(); } } var style2prop3 = (function(){ var f = function(s){ return s.charAt(1).toUpperCase(); }; return function(str){str.replace(/-[a-z]/g, f)}; })(); var style2prop4 = (function(){ function f(s){ return s.charAt(1).toUpperCase(); } return function(str){str.replace(/-[a-z]/g, f)}; })(); function style2prop5(str){ return str.replace(/-[a-z]/g, ff); } function ff(s){ return s.charAt(1).toUpperCase(); } function style2prop6(str){ return str.replace(/-[a-z]/g, arguments.callee.f); } style2prop6.f = function(s){ return s.charAt(1).toUpperCase(); } Function.prototype.time = function(){ var s = new Date().getTime(); for(var i=0;i<10000;i++){ var result = this.apply(null, arguments); } console.log("time:" + ((new Date().getTime() - s)/10000)); return result; } style2prop.time("hoge-hogehoge"); //0.0186 style2prop2.time("hoge-hogehoge"); //0.0188 style2prop3.time("hoge-hogehoge"); //0.0223 style2prop4.time("hoge-hogehoge")/ //0.0223 style2prop5.time("hoge-hogehoge"); //0.0171 style2prop6.time("hoge-hogehoge"); //0.0233
あらぁ。
結局内部関数を使いつつ速度をもっと速くする方法はわからず。。
追記
id:brazilさんに教えてもらった方法も計測。
function style2prop(str){ return str.replace(/-[a-z]/g, function(str) { return str.charAt(1).toUpperCase(); }); } function style2prop_global(str){ return str.replace(/-[a-z]/g, ff); } function ff(s){ return s.charAt(1).toUpperCase(); } function style2prop_property(str){ return str.replace(/-[a-z]/g, arguments.callee.f); } style2prop_property.f = function(s){ return s.charAt(1).toUpperCase(); } // ↓教えてもらった方法 function style2prop_initialize(str){ function f (s){ return s.charAt(1).toUpperCase(); } return (style2prop_initialize = function(str){ return str.replace(/-[a-z]/g, f); }).apply(null, arguments); } with(DEF()){ // 計測結果 ↓お。速い print(test()); // 290, 280, 357 ,285 by spidermonkey function test(){ var TIMES= 10000; var timer = new Timer(); var target = "hoge-hogehoge"; timer.start(); for(var i=0;i<TIMES;i++){ style2prop(target); } timer.stop(); timer.start(); for(var i=0;i<TIMES;i++){ style2prop_global(target); } timer.stop(); timer.start(); for(var i=0;i<TIMES;i++){ style2prop_property(target); } timer.stop(); timer.start(); for(var i=0;i<TIMES;i++){ style2prop_initialize(target); } timer.stop(); return timer.times; } } function DEF(){ function Timer(){} Timer.prototype = { index:0, times:[], start:function(i){ this.times[this.index] = new Date().getTime(); }, stop:function(i){ var time = new Date().getTime(); var s = this.times[this.index]; this.times[this.index] = time - s; this.index++; } }; return {Timer:Timer}; }
計測方法を変えたのは、関数定義を渡して実行する今までの計測方法だとstyle2prop_initializeの良さがなくなるから(毎回関数定義を作ることになるから)。
結果グローバルの関数を参照する方法の次に、最初の呼び出しのときに関数定義を作るstyle2prop_initializeの方法が速いことが分かりました。
それと、この計測をやっててわかったことを次の日記に書いておきます。