JavaScriptで引数を束縛したい場合、クロージャかbindを使うのだが…
function plus(x, y) { return x + y; } function multiply(x, y) { return x * y; } // Function.prototype.bindで束縛 const plus1 = plus.bind(null, 1); plus1(5); // => 6 // closureで束縛 function closure(func, param) { return function(index) { return func(param, index); }; } const twice = closure(multiply, 2); twice(5); // => 10
なんとなく、どちらが速いのか気になったので比べてみた。
console.time('bind'); for (let i = 0; i < 100000; i++) { const plusX = plus.bind(null, i); const multiplyX = multiply.bind(null, i); for (let j = 0; j < 10; j++) { plusX(j) + multiplyX(j); } } console.timeEnd('bind'); console.time('closure'); for (let i = 0; i < 100000; i++) { const plusX = closure(plus, i); const multiplyX = closure(multiply, i); for (let j = 0; j < 10; j++) { plusX(j) + multiplyX(j); } } console.timeEnd('closure');
結果
$ nvm use v6 Now using node versions/node/v6.2.1 $ node speed.js bind: 106.394ms closure: 33.421ms
node v6.2.1ではクロージャを使うほうが3倍ほど高速らしい。
node ver.4でも測定
$ nvm use v4 Now using node versions/node/v4.4.5 $ node speed.js bind: 949ms closure: 33ms
node ver.4では30倍程度の差がついた。というよりも、ver.4とver.6でFunction.prototype.bindが10倍も高速になっている。
node v4.4.5にはV8 v4.5、node v6.2.1にはV8 v5.0が搭載されている。メジャーバージョンアップで大きな最適化が施されていることがわかる。さすがGoogleである。未だJSエンジンの進化は止まらず。
なおこのコードをFirefoxとChromeの最新版で比較してみると…
Chrome 51.0.2704.79
bind: 127.187ms closure: 34.819ms
Firefox 47.0
bind: タイマー開始 bind: 36.4ms closure: タイマー開始 closure: 6.85ms
Firefox圧勝!