これは、先日の記事「JavaScriptの無名関数とクラス」の続きです。
外から呼び出せないなら、中でやればいいじゃない!
今しがた、他の事をしていたら突然に閃いた。すごい思い込みで無駄な事をしていた。こないだ書いた記事、あれオブジェクト化する必要はなかったんだ。
自分がやりたかった事は、ボタンをonclickしたら、setCookie関数を走らせたかっただけで、そのために無名関数の中のfunctionをprototypeにするということを考えた。なぜなら、無名関数の中の関数はonclickで呼び出せないから。
記事の中で、ボタンのないバージョンと、あるバージョンの2つを走らせたいという考えもあった。「2つ走らせるならオブジェクト」という発想が先行した。
でも、そうじゃなかった。「無名関数の中の関数はonclickで呼び出せない」のなら、「無名関数の中でonclickのコールバックを書き込めばいい」だけだったんだ!
つまり、元のソースの終盤の部分を、少し書き換えるだけでよかった。
if( !targetDay ) { targetDay = addDay( LIMIT_DAY ).getTime(); setCookie( COOKIE_NAME, targetDay + '', SHELF_LIFE ); } (function () { var text = '次回まで約'; var s = (targetDay - (new Date).getTime()) / 1000 |0; if (s < 0) text = TIMEOUT_MESS; else { text += padding( s % 86400 / 3600 |0) + '時間' + padding( s % 3600 / 60 |0) + '分' + padding( s % 60 |0) + '秒です。'; setTimeout (arguments.callee, 1000); } node.firstChild.nodeValue = text; })();
上のソースは、下のように書き換えても同じ。
function reset(){ targetDay = addDay( LIMIT_DAY ).getTime(); setCookie( COOKIE_NAME, targetDay + '', SHELF_LIFE ); } function load() { var text = '次回まで約'; var s = (targetDay - (new Date).getTime()) / 1000 |0; if (s < 0) text = TIMEOUT_MESS; else { text += padding( s % 86400 / 3600 |0) + '時間' + padding( s % 3600 / 60 |0) + '分' + padding( s % 60 |0) + '秒です。'; setTimeout (load, 1000); } node.firstChild.nodeValue = text; } if( !targetDay ) { reset(); } load();
あとは、<input type="button" id="messBtn" value="リセット" /> とでもして、次のcallbackを無名関数の中から書き込むだけで事足りた。
document.getElementById('messBtn').onclick=function(){ reset(); load(); };
これで実際に動いている。
次回
タイマーをこれなら前回、global宣言したvar countdownも必要ない。出来る限りglobalではなくlocalで宣言は済ませたい。
もし、2つ走らせたいなら、無名関数をやめて、関数に名前をつければいい。その時、表示領域のidを引数に加えるだけでよかった。ただし、prototypeと違って無駄なメモリーを食うけれど。そのメモリー消費も微々たるもの。ブログのたったひとつの記事のためにオブジェクトにするのが効率的かどうかという話だな。実際、今やってみたら、この書き換え作業は2〜3分で出来た。前回はthisをつけるのに数分要している。
今回は元のソースを書いたbabu_babu_babooさんにやんわりと指摘を受けていた。けど、その真意を理解できないでいた。ずっと頭の中で気になっていたんだけど、突然に閃いた。こういうことだったんだ。なんでもかんでもオブジェクトにすればいいってもんじゃないな。
これはプログラミングに限らず言えることだけど、自分一人で考えていると、ひとりよがりの結論になりがちだ。指摘をされるまで気がつかない事というものはある。せっかくブログがあるんだから情報は表に出して、いろいろな意見を聞いた方がいいのかもしれない。と、今回は思いました。
最終的なソースコード
前回のコードでも動作は問題ないので、前回のソースを使っているマスクドライダー17号さんが下のソースに書き換える必要はありません。(書き換えてもいいけど、同じ事です)
<style type="text/css"> p#mess{ font-size:200%; } </style> <p id="mess">次回</p> タイマーを<input type="button" id="messBtn" value="リセット" /> <script type="text/javascript"> <!-- (function (doc) { function addDay ( day, date ) { if( 'number' !== typeof day ) day = 0; if( 'object' !== typeof date ) date = new Date; date.setDate( date.getDate() + day ); return date; } function getCookie ( name ) { name = encodeURIComponent( name ).replace( /([.*()]) /g, '\\$1' ); var value = doc.cookie.match( RegExp( name + '\\s*=\\s*(.*?)(?:[\\s;,]|$)' ) ); return value ? decodeURIComponent( value[1] ): ''; } function setCookie ( name, value, day, path, domain ) { return doc.cookie = encodeURIComponent (name) + '=' + encodeURIComponent (value) + '; ' + 'expires=' + ( addDay(day) ).toUTCString () + '; ' + (path ? 'path=' + encodeURI (path) + '; ': '') + (domain ? 'domain=' + encodeURI (domain) + '; ': ''); } function padding ( n ) { return n < 10 ? '0' + n: n; } var COOKIE_NAME = 'myCount'; var LIMIT_DAY = 1; var SHELF_LIFE = 10; var TIMEOUT_MESS = '24時間以上経過しました!!'; var node = doc.getElementById( 'mess' ); var targetDay = parseInt( getCookie( COOKIE_NAME ) ); function reset(){ targetDay = addDay( LIMIT_DAY ).getTime(); setCookie( COOKIE_NAME, targetDay + '', SHELF_LIFE ); } function load() { var text = '次回まで約'; var s = (targetDay - (new Date).getTime()) / 1000 |0; if (s < 0) text = TIMEOUT_MESS; else { text += padding( s % 86400 / 3600 |0) + '時間' + padding( s % 3600 / 60 |0) + '分' + padding( s % 60 |0) + '秒です。'; setTimeout (load, 1000); } node.firstChild.nodeValue = text; } if( !targetDay ) { reset(); } load(); document.getElementById('messBtn').onclick=function(){ reset(); load(); }; })(this.document); //--> </script>