・ 指定回数繰り返しさせる関数
・ true の間、延々と繰り返しさせる関数(カウンター付)
を前回の、「遅延させるだけの関数」から作成します。
「3歩または5歩進んで止まる」を100回繰り返します。
・ 指定回数繰り返しさせる関数
・ 角度をずらす関数
を使ってわずか2行で仕上がります。
・ 指定回数繰り返しさせる関数
・ 角度をずらす関数
を使ってわずか2行で仕上がります。
■ 動作確認
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 times(fn, tm, cnt){
var id = Math.random() + "-" + (new Date()).getTime();
var cb = function (){
var slf = this, arg = arguments;
if(!slf[id]){slf = {self:slf}; slf[id] = 0;}
slf[id]++;
var tid = setTimeout(function (){
clearTimeout(tid);
fn.apply(slf.self, arg);
if(slf[id] < cnt) cb.apply(slf, arg);
}, tm);
}
return cb;
}
var id = Math.random() + "-" + (new Date()).getTime();
var cb = function (){
var slf = this, arg = arguments;
if(!slf[id]){slf = {self:slf}; slf[id] = 0;}
slf[id]++;
var tid = setTimeout(function (){
clearTimeout(tid);
fn.apply(slf.self, arg);
if(slf[id] < cnt) cb.apply(slf, arg);
}, tm);
}
return cb;
}
今回からは、利用価値が上がると思いますので、ちゃんと clearTimeout を使っていきます。また、このコードでは setTimeout を使ってますが、上のサンプルでは setInterval を使ってます。(こっちのが好きなのでw)
使用例: fn2 = times(fn1, tm, n);
fn2 に、tm 時間(msec)ごとに n 回、関数 fn1 と同じ動作をする関数が返されます。
ローカルで定義した新しい関数(cb)/繰り返したい元関数(fn1)と同一の関数の2つを setTimeout で呼び出しています。
ただ、カウンター(何回呼び出されたのか?)を保持させる変数は、グローバルにしたくないので、cb を呼び出すときに this に加えて一緒に渡してやっています。
※ this は持ち回されるため、カウンターの保持に利用しています(times 関数内でのみです。他への影響はないと考えていいと思います)。ただ、何の対策もないと times(times(func, 2000, 2), 7000, 4) などのような場合にカウンターの競合が起こって誤動作します。そのため、カウンターを保持するための識別子(コード中では id)は、17桁のランダムな数値と現在時間(msec)を使っています。
※ fn.apply(slf.self, arg); を var tid = setTimeout(function (){ の前に出すと、初回1回目は遅延せずに実行されます。上記サンプルは、そうなっています。
※ 上のコードの場合、setTimeout と setInterval は相互互換です。好きな方を使ってください。setTimeout はズレが生じることがありましたが、現在は未調査です。
■ サンプルに関して
上記サンプルのURLはこちら
右クリック --> ソースの表示や、ファイル --> 名前をつけて保存で取得してください。
サンプルでは4種の「動き」が必要になります。クラスを作成したり、1つの柔軟で強力な関数を作ったりと色々考えられます。
times() は、指定時間、指定回数繰り返しさせるようにして複製するので、今回のように規則的な動作の場合は、はるかにラクにできます。
サンプルでは、times() のほか move()(角度をずらす関数)があるだけで、
times(times(move, 100, 3), 1000, 100)(対象object1);
times(times(move, 150, 5), 1000, 100)(対象object2);
の2行で処理しています。結局これは・・・
var obj1move = times(move, 100, 3);
var obj2move = times(move, 150, 5);
var obj1round = times(obj1move, 1000, 100)
var obj2round = times(obj2move, 1000, 100)
のように4つの関数に複製させたのち、実行するのと等価です。
true の間、延々と繰り返しさせる関数(カウンター付)
function ticker(fn, tm){
var id = Math.random() + "-" + (new Date()).getTime();
var cb = function (){
var slf = this, arg = arguments;
if(!slf[id]){slf = {self:slf}; slf[id] = 0;}
slf[id]++;
var tid = setTimeout(function (){
clearTimeout(tid);
if(fn.apply({self:slf.self, count:slf[id]}, arg) == true)
cb.apply(slf, arg);
}, tm);
}
return cb;
}
var id = Math.random() + "-" + (new Date()).getTime();
var cb = function (){
var slf = this, arg = arguments;
if(!slf[id]){slf = {self:slf}; slf[id] = 0;}
slf[id]++;
var tid = setTimeout(function (){
clearTimeout(tid);
if(fn.apply({self:slf.self, count:slf[id]}, arg) == true)
cb.apply(slf, arg);
}, tm);
}
return cb;
}
使用例: fn2 = ticker(fn1, tm);
関数 fn1 の複製が true を返す限り、tm 時間(msec)ごとに、関数 fn1 の複製が実行される関数が、fn2 に返されます。
「指定回数繰り返しさせる関数」(times)と考え方は、まったく同じです。
times では、ローカルで新規に定義した関数(cb)がカウントして、指定回数にまで繰り返していましたが、ticker では、this を用いて、関数 fn1 の複製へも呼び出し回数を報告しています。
こちらも ticker(ticker(func, 2000), 7000); と入れ子にしても問題ありません。
■ テスト
function alerm(val){
if(this.self != window) var slf = this.self; else var slf = "";
alert(slf + val + "ごと" + this.count + "回目");
if(this.count < 5) return true;
}
上記関数があるとして。
var newFunc = ticker(alerm, 2000);
newFunc.call("this を渡して", "2秒");
とすれば試せます。call や apply が分からない人は、newFunc("2秒"); でも実行できますので、試してみてください。
2秒おきに5回、アラートが起動します。
要点としては、カウンタは、呼び出される関数内で this.count が保持しているということです。そうなると、今までの関数と違って注意する点は、this が汚れているということです。
※ 通常の this は this.self で取得できます。
※ 汚れるといっても元のオブジェクトは無傷です。
※ if(fn.apply・・・ の1行を var tid = setTimeout(function (){ の前に出すと、初回1回目は遅延せずに実行されます。
※ 上のコードの場合、setTimeout と setInterval は相互互換です。
※ なぜ this なのか?・・・もう当然というか^^
・ this が汚れて困るのは上級者だけ。つまりなんとでも対処できるハズw
・ arguments や、そのためだけのラッピングを行うより断然ラク!
・ this.self にしても this.count にしても言葉的に分かりやすい。^^
■ サンプルに関して
上記サンプルのURLはこちら
右クリック --> ソースの表示や、ファイル --> 名前をつけて保存で取得してください。
こちらの ticker は、逆に true が返ってきたら止まるようにして変形させてます。if(!fn.app・・・ の ! を付けただけ。サンプルではこちらの方がラクなので・・・てかその方が一般的にも使いやすいかも。
3匹のイモムシ、種類や個性があるのですが、分かります?イモムシ1匹にシャクトリムシ2匹。シャクトリムシは、猪突猛進タイプときょろきょろ迷うタイプかな。あんまヤリすぎると虫らしくないのでちょいと微妙で止めといた。
クラス定義してインスタンスにしても洗練されたコードで出来ますが、こちらはこちらでかなり簡潔。各関数以外、グローバル汚して無いのもいいかな。
ちなみに説明は無しです。ちょっと大変なのでw 分からないところを言って頂ければお答えします。





全然理解できん。
>通りすがりさん
おっしゃって頂ければ回答しやすよ。
>おちょぼさん
ま、基本的なものしか使ってないので。
実際問題短けりゃ良いというものでもなかったりします。
チームで開発する場合は、分かりやすさ、読みやすさは重要かと。
ま、ウチは零細なので、チーム開発できないんで好き放題やってますがw
通りすがりさんのおっしゃってるのは、おそらくこんな意味が含まれる?