latest log

酩酊状態で書いたエンジニアポエムです。酩酊状態で読んでください。

Number#lazy をやめて Number#wait にしたいメモ

Number#lazy を作ってみて、
メソッド名の改善と引数の並びに改善可能な点を感じたので、
Number#lazy は廃止して Number#wait にして、さらに引数変えるかもよの巻。

何を考えてAPIの変更を行なったかメモ

Number#lazy の実装はこうなっています。

// Number#lazy
function Number_lazy(fn,     // @arg Function: callback
                     args,   // @arg Mix/MixArray(= undefined): callback(args)
                     that) { // @arg this(= null):
                             // @return Number: atom (setTimeout timer id)
                             // @help: Number#Number.prototype.lazy
                             // @desc: lazy callback function
//{@assert
    mm.allow(fn,   FN);
    mm.allow(args, ARRAY | UNDEF);
//}@assert

    return setTimeout(function() {
                fn.apply(that || null, Array.isArray(args) ? args : [args]);
            }, this * 1000);
}

Number#wait はこうなる予定です。

function Number_wait(fn_that       // @arg Function/FunctionAndThatArray: callback or [callback, that]
                     /*, ... */) { // @var_arg Mix(= undefined): callback.apply(that, var_args)
                                   // @this Number: delay seconds
                                   // @return Number: atom (setTimeout timer id)
                                   // @help: Number#Number.prototype.wait
                                   // @desc: lazy evaluate
//{@assert
    mm.allow(fn_that, FN | ARRAY);
    if (Array.isArray(fn_that)) {
        if (!mm.isFn(fn_that[0]) || fn_that.length !== 2) {
            throw new Error("BAD_ARG");
        }
    }
//}@assert

    var fn   = fn_that[0] || fn_that,
        that = fn_that[1] || null,
        args = Array.prototype.slice.call(arguments, 1);

    return setTimeout(function() {
                fn.apply(that, args);
            }, this * 1000);
}

Number#lazy は 0..lazy(コールバック関数, [引数], this) の形で指定しますが、this を渡すために 0..lazy(fn, [], this) とするのが無駄に感じられる人もいるということで、 Number#wait では 0..wait(コールバック引数, var_args) または 0..wait([コールバック引数, this], var_args) の形で指定できるように、引数の構造を変えています。

0..lazy(fn);                          // fn() を遅延評価
0..lazy(fn, ["arg1", "arg2"]);        // fn("arg1", "arg2") を遅延評価
0..lazy(fn, [], this);                // this.fn() を遅延評価
0..lazy(fn, ["arg1", "arg2"], this);  // this.fn("arg1", "arg2") を遅延評価

0..wait(fn);                          // fn() を遅延評価
0..wait(fn, "arg1", "arg2");          // fn("arg1", "arg2") を遅延評価
0..wait([fn, this]);                  // this.fn() を遅延評価
0..wait([fn, this], "arg1", "arg2");  // this.fn("arg1", "arg2") を遅延評価

Number#wait の引数の並びのほうが若干短く書けるし、見慣れると自然に感じられるかなーと。
# Number#lazy の最後に this を指定する書式は、Array#forEach 系がそんな感じだから、それに発想が引きづられてしまってた感じですね


Number#wait の引数展開部分は、正しくは↓こう書くべきなんだろうけど、

    var fn, that, args = Array_slice(arguments, 1);

    if (Array.isArray(fn_that)) {
        fn = fn_that[0];
        that = fn_that[1];
    } else {
        fn = fn_that;
    }

↓のように、関数オブジェクトに 0 と 1 を生やし適切な値を設定しておくと、自己参照呼び出しも可能になるなーと考え、あのようにしています。裏ワザ的用法で知っていれば使えるということで。

function aaa(a, b, c) {
    console.log(123, a, b, c, this.hoge); // 123 1 2 3 "hogehoge" 
}
aaa[0] = aaa;
aaa[1] = aaa;
aaa["hoge"] = "hogehoge";

2..wait(aaa, 1, 2, 3);

jQuery のように「関数なんだけど、配列の要素が格納されている変造オブジェクト」を Number#wait に食べさせると、誤作動起こす可能性があるので、0..wait(jQuery, "arg") の結果は不定になります。
でも 0..wait(jQuery, "arg") なコードは絶対に書かれないだろうから、それは織り込み済み(designed)ってことになります。