JavaScript: The Good Parts より、コード断片のメモ。
p.39 Closure
以下のような HTML において、a ~ b をクリックしたときに、0 ~ 3 を出力したい。
<ol> <li>a</li> <li>b</li> <li>c</li> <li>d</li> </ol>
何も考えないで書くとこうなる。nodes には li のコレクションが渡っている。
var addHanlders = function(nodes) { for (var i = 0; i < nodes.length; i++) { nodes[i].onclick = function() { console.log(i); }; } };
どれをクリックしても 4 が表示される。
クロージャを使うと正しく動作する。
var addHanlders = function(nodes) { for (var i = 0; i < nodes.length; i++) { nodes[i].onclick = function(i) { return function() { console.log(i); } }(i); } };
p.41 Curry
カリー化について。
Function.prototype.curry = function() { var slice = Array.prototype.slice; var args = slice.apply(arguments); var scope = this; return function() { return scope.apply(null, args.concat(slice.apply(arguments))); }; };
以下の単純な関数をカリー化してみる。
function add(a, b) { return a + b; } var add1 = add.curry(1); console.log(add1(6)); //7
p.44 Memoization
メモ化について。理解できていない。
以下は、フィボナッチ数列を出力する関数。
var fibonacci = function(n) { return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); };
項数を 10 で実行すると、442 回も実行されて無駄がある。そこでメモ化。
var fibonacci = function() { var memo = [0, 1]; var fib = function(n) { times++; var result = memo[n]; if (typeof result !== "number") { result = fib(n - 1) + fib(n - 2); memo[n] = result; } return result; }; return fib; }();
呼び出しが 29 回に減った。
memoizer として共通化するとこうなる。
var memoizer = function(memo, fundamental) { var shell = function(n) { var result = memo[n]; if (typeof result !== "number") { result = fundamental(shell, n); memo[n] = result; } return result; }; return shell; }; var fibonacci = memoizer([0, 1], function(shell, n) { return shell(n - 1) + shell(n - 2); });