MochiKit を使う際に、追加している関数を晒してみる(その2.partial)

id:cooldaemon:20070429:1177857285 の続き。
Mochikit.Base.partial は、前方から引数を束縛するのですが、任意の位置の引数を束縛したかったので、my_partial を作ってみました。

source の前に実例

var base_func = function () {
  map(function (arg, i) {log(i + ' = ' + arg);}, arguments, count());
};

var lazy_base_func = function () {
  var str = '';
  forEach(arguments, function (arg) {str += arg;})
  return str;
};

var new_func = my_partial(base_func, 'a', hole, 'c', hole, lazy(lazy_base_func, 2));
new_func('b', 'd', 'e', 'f', 'g');

上記を実行すると…

0 = a
1 = b
2 = c
3 = d
4 = ef
5 = g

と出力されます。

Mochikit.Base.partial と似ている箇所

my_partial は、第一引数に引数を束縛したい関数、第二引数以降に束縛したい引数を渡して使います。

Mochikit.Base.partial と明らかに異なる箇所

hole を第二引数以降にすると、その箇所に、新しく my_partial で作った関数の引数が渡されます。
また、lazy 関数の戻り値を引数として渡すと、my_partial で作った関数を実行する度に、lazy 関数の第一引数として渡した関数を実行し、その戻り値を、my_partial で作った関数の引数とします。
lazy 関数の第二引数は、第一引数に渡した関数に、my_partial で作った関数に渡した引数を幾つ渡すのか?を指定します。(省略すると、0 個になります)

で、source

下記、名前空間無視してます。ゴメンナサイ。
その他の突っ込み大歓迎です。

var Lazy = function (func) {
  var m = MochiKit.Base;
  this.func = func;
  this.arg_count = m.isUndefinedOrNull(arguments[1]) ? 0 : arguments[1];
};

var hole = {};
var lazy = function (func, arg_count) {
  return new Lazy(func, arg_count);
};

var my_partial = function (func) {
  var m = MochiKit.Base;
  var it = MochiKit.Iter;

  var base_args = m.extend(null, arguments, 1);

  return function () {
    var args = arguments;
    args.shift = Array.prototype.shift;

    var new_args = [];

    it.forEach(base_args, function (arg) {
      if (arg !== hole && !(arg instanceof Lazy)) {
        new_args.push(arg);
        return;
      }

      if (arg == hole) {
        if (!m.isUndefinedOrNull(args[0])) {
          new_args.push(args.shift());
        }
        return;
      }

      var lazy_args = [];
      for (var count = 0; count < arg.arg_count; count++) {
        if (m.isUndefinedOrNull(args[0])) {
          break;
        }
        lazy_args.push(args.shift());
      }
      new_args.push(arg.func.apply(this, lazy_args));
    });

    it.forEach(args, function (arg) {
      new_args.push(arg);
    });

    func.apply(this, new_args);
  }
}

関数呼び出す度に、こんなんしてたら重いなぁ…。