20150524 - kyosen/javascript-ninja GitHub Wiki

第5章 クロージャ

5.1 クロージャの仕組み

5.2 クロージャを利用する

  • 5.2.2 Tips 「$記号を変数名のサフィックス(後置)またはプリフィックス(前置)として使う」 どちらにしている?(辻)
    • サフィックス(後置)は見たことがない。
    • $だけの変数名はjQuery自体のオブジェクトを指す。

5.3 呼び出しコンテクストをバインドする

  • 「ところで、Prototypeライブラリのbind()は〜」「この重要なポイントが異なるapply()とcall()は〜とても便利に使える。」がよくわからない。(辻)
    • 「bind()」と「apply()とcall()」の違いを述べている。

5.4 関数の部分適用

  • 「関数の引数群のうち最初のいくつかを記入した新しい関数を返すテクニックは、一般にカリー化(currying)と呼ばれる。」これは本当にカリー化?(伊藤)

  • split(/,¥s*/)の引数は何?(辻)

    • 引数は1つだけ。正規表現リテラルになっている。
  • リスト5-11 Array.prototype.slice.call(arguments)はargumentsをArrayオブジェクトに変換するということ?(井谷)

    • callの第一引数はコンテキストになるオブジェクト
    • sliceは配列の一部を取り出すメソッド。引数が省略されれば配列全体を取り出す。
    • つまり上記で正しい。
  • リスト5-11 カリー化関数

    • 3行目のargumentsはcurryが呼ばれた時の引数 -> argsに保存される
    • 6行目のargumentsはカリー化された関数が呼ばれた時の引数
    • 本来のカリー化は部分適用しやすい形にすること。まだ部分適用していない状態。
    • 以下のコードは部分適用までしているのでカリー化ではない? JavaScriptでは仕方がない?
    • curry関数を定義することがカリー化。curry関数を呼び出すことが部分適用。
function div(x, y) { return x / y; }
var cdiv = div.curry(1);
cdiv(2); // div.apply(this, [1].concat([2]))
  • (追記)curry関数は以下のような実装だと正しい?(矢野)
    • 引数がすべて揃ったら元の関数を呼び出す(Functionオブジェクトのlengthで仮引数の個数がわかる)
Function.prototype.curry = function () {
  var fn = this;
  return function () {
    var args = Array.prototype.slice.call(arguments);
    if (fn.length <= args.length)
      return fn.apply(this, args);

    var cfn = arguments.callee;
    return function () {
      return cfn.apply(this, args.concat(Array.prototype.slice.call(arguments)));
    };
  };
};
function sum(a, b, c) { return a + b + c; }
var csum = sum.curry();

csum(1)        // => [Function]
csum(1)(2)     // => [Function]
csum(1)(2)(3)  // => 6

csum(4, 5)     // => [Function]
csum(4, 5)(6)  // => 15

5.5 関数の振る舞いをオーバーライドする

5.6 即時関数

  • 5.6.1 「短い名前でコードを読みやすくする」Object.extendのコード例で、同じオブジェクト(v._getAttrなど)を別の名前にしている(href, src, typeなど)。(井谷)
    • 例が悪い?
    • 引数によって動作が変わるので正しい?

5.7 まとめ