2006年11月14日

最終形態?自由に繰返す関数として複製(遅延/繰返し/回数指定して function を複製する3)

1,2を包含して、さらに機能アップした機能過多w関数を作成しました。
但し、最初一回目は遅延させません。

繰り返しの場合は、1回目の遅延なんてやはりレアケースですねw
機能的には以下です。

  1. インターバル時間、呼出回数を指定して関数を複製する。
  2. 関数に現在の呼出回数を渡すことができる。
  3. 関数に予定された呼出回数と呼び出し間隔を渡すことができる。
  4. 関数から、予定された呼出回数と呼び出し間隔が随時変更できる。
  5. 終了時に他関数を起動できる。
  6. 関数が false を返せば、止められる。
  7. 関数が false を返さず、回数指定もなければ延々と繰り返す。
  8. 入れ子でも、this.self で this を取得できる。
  9. 入れ子でも、各段階の予定された呼出回数と呼び出し間隔が、関数から取得・変更できる
※ 上記での「関数」とは、複製された関数になります。

前回、ほぼ最終形とのたまったのは誰だったのか・・・
ま、色々いじってるとどんどん欲が出てくるw


■ 動作確認
IE 4.0/5.0/5.5/6.0
FF 1.0/1.5
NS 6.2/7.1
OP 7.02/8.53/9.01
Sleipnir 2.30




 リピート関数

function repeat(fn, tm, cnt, ebfn){
  if(typeof(cnt) == 'undefined') cnt = 'continue';
  var id = (Math.random() + '' + (new Date()).getTime()).replace('0.', '');
  var cb = function (){
    var slf = this, arg = arguments;
    if(slf.id != id){
      slf = {parent:this, count:0, max:cnt, interval:tm, id:id};
      if(this.id && this['recog' + this.id]){
        slf['recog' + slf.id] = this['recog' + this.id] + 1;
        slf.self = this.self;
      }else{
        slf['recog' + slf.id] = 1;
        slf.self = this;
      }
    }
    slf.count++;
    if((fn.apply(slf, arg) != false) & (cnt == 'continue' || slf.count < slf.max)){
      var tid = setTimeout(function (){
        clearTimeout(tid);
        cb.apply(slf, arg);
      }, slf.interval);
    }else if(typeof(ebfn) == 'function') ebfn.apply(slf, arg);
  }
  return cb;
}

■ 使い方

newFunc = repeat(orgFunc, tm, cnt*, cbFunc*);

* は、省略可能です。
newFunc へ、インターバル時間を tm ミリ秒、 呼び出し回数を cnt 回とする orgFunc の複製が返されます。
cbFunc は、繰り返し終了時に呼び出す関数です。
また、orgFunc の複製が false を返した場合、 newFunc はストップします。

■ テスト1(動作確認)
function alerm(i){
  //this.interval = this.interval + 1000;//★
  return confirm(
    i + this.self + "は " +
    this.interval + "msec の間隔をあけて呼び出されます。\n現在 " +
    this.count + " 回起動しました。残り " +
    (this.max - this.count) + " 回起動します。\n\n" +
    "続けますか?"
  );
}
var func = repeat(alerm, 2000, 5);// 複製
func.call("このテスト", "Hello!\n\n");// call 付きで起動
// func("Hello!\n\n"); でも OK ですが [object] の文字が表示されます。

 こちらから動作確認できます。
最後2行が、関数 alerm の複製と起動になります。

■ 呼び出し回数等の取得・変更方法

複製される関数側(上記テストなら alerm)から、呼び出し回数の取得・変更ができます。複製される関数内で、下記にアクセスして状態を取得・変更できます。(テスト1参照)
  • [this.self] apply や call で渡された this が保持されます。
  • [this.interval] 予定される次回呼び出しまでの間隔(msec)。変更可。
  • [this.count] 呼び出された回数。変更可w
  • [this.max] 終了予定の回数。変更可。
  • [this.id] 複製時に与えられる固有のID。変更不可。
  • [this.recog + [this.id]] 複製された層の数。変更不可。
  • [this.parent] アクセスした層の上の層。変更不可。

※ 呼び出し回数未設定だと this.count <-- 'continue' です。
※ id, recog, parent は変更すると誤動作します。
※ this.recog はその関数が何回複製されたのかを保持しています。
※ 繰り返し終了時に呼び出される関数も同様です。
※ repeat の機能を使わなくても count == max で元関数から終了を確認できます。

■ 変更できるかどうかの確認

テスト1のコメントアウト「★」の先頭の // を外してやると、起動時間が2秒、3秒、4秒・・・の様になります。


■ 入れ子にする場合

newFunc = repeat(repeat(repeat(orgFunc, tm1, cnt1), tm2, cnt2), tm3, cnt3);

など。何層でもOKです。

・ call などで渡した this の取得
今までは、入れ子の回数分 this.self.self.self とやれば、this が取得できたのですが、これが面倒ということもあります。
入れ子で複製した場合、何層ラッピングしても this.self で call や apply などで渡した this を取得できます。

・ 上層(表層)の this の取得
上記コードだと、orgFunc 内で this.interval とすると tm1 を取得できますが、上層の this は this.parent で取得できます。
てことで、tm2 や、tm3 など上層のプロパティを取得するには this.parent.interval とか this.parent.parent.interval などとします。

・ アクセスしている層が何層目か?
this[recog + this.id] で、何層目かが分かります。上層(表層から数えて)
なので、this.parent[recog + this.parent.id] とすると上層が何層目かが分かります。(上層が無ければ undefined)
上の例では、this[recog + this.id] は 3 、this.parent[recog + this.parent.id] は 2 です。

・ 終了確認
入れ子の場合、関数の呼び出しは「直列」ではありません。継時的にそれぞれ呼び出されるため時間差はあるものの構造的には「並列」。
そのため、終了時に起動される関数はあまり意味をなさないハズ。
これら入れ子状に複製された一連の流れの「最後」の終了を取得したい場合は、元関数内で、count == max をそれぞれの層に対して確認します。

■ 入れ子にする場合のテスト

テストはこちら

おまけ
posted by HiFa at 16:38 | 🌁 | Comment(0) | TrackBack(0) | JavaScript雑感 | このブログの読者になる | 更新情報をチェックする
>>> スパムコメントは消してますよん。 お互い無駄な労力は避けましょう。 <<<

この記事へのコメント

コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/27461731
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。