先に示した setTimeout()
を利用したカウントダウンプログラムを見てみよう。
countdown.js
(再掲)
// 例: 変数の隠蔽化 var count = 10, tmID, infobox = document.getElementById("timeout"); function countDown() { if (--count == 0) { infobox.innerHTML = "ぼかーん"; } else { infobox.innerHTML = count + "秒前"; tmID = setTimeout(countDown, 1000); } } function startCountDown() { tmID = setTimeout(countDown, 1000); infobox.removeEventListener("click", startCountDown, false); infobox.addEventListener("click", stopCountDown, false); } function stopCountDown() { clearTimeout(tmID); infobox.innerHTML = "停めました。"; infobox.removeEventListener("click", stopCountDown, false); } infobox.addEventListener("click", startCountDown, false);
このプログラムではカウントダウン処理に必要な変数として
count, tID, infobox
の3つを利用している。
これは JavaScript 処理系のトップレベルの名前空間に居座りグローバル変数となる。
グローバル変数を多用すると、同じWeb文書内で別の JavaScript
プログラムをロードした場合にかち合う可能性がある。
個人用途に確実に限定されるプログラムでないかぎり、 グローバルシンボルの多用は避けるべきである。
関数定義内で宣言した変数は、関数内でしか有効にならないことを利用し、 プログラムに必要な一連の変数、関数定義を包含する関数1つに集約することで、 グローバルシンボルはその外側関数1つだけで済ませられる。
規模のあまり大きくない JavaScript プログラムでは以下のように書くことでグローバル変数多用を回避できる。
// 例: 変数を隠蔽した書き方 function CountDown() { var count = 10, tmID, infobox = document.getElementById("timeout"); function countDown() { if (--count == 0) { infobox.innerHTML = "ぼかーん"; } else { infobox.innerHTML = count + "秒前"; tmID = setTimeout(countDown, 1000); } } function startCountDown() { tmID = setTimeout(countDown, 1000); infobox.removeEventListener("click", startCountDown, false); infobox.addEventListener("click", stopCountDown, false); } function stopCountDown() { clearTimeout(tmID); infobox.innerHTML = "停めました。"; infobox.removeEventListener("click", stopCountDown, false); } infobox.addEventListener("click", startCountDown, false); }; document.addEventListener("DOMContentLoaded", function() { CountDown();}, false); //document.addEventListener("DOMContentLoaded", CountDown, false);
くりっくしてね
末尾で window オブジェクトの load イベントに渡しているリスナの、
function() {CountDown();}
は、名前のない関数定義で、無名関数 というオブジェクトである。
以後例示するプログラムではグローバルシンボルの軽減をはかった方がよいと 思われるものは、関数スコープに閉じ込めた書き方を示す。 現実的には、第三者が利用することを前提としたライブラリプログラム等では 1つの関数オブジェクトだけに値を持たせるには不十分な場合もあり、 そのようなときは複写して安全に利用できる関数オブジェクトを定義する必要がある。
なお、上記のプログラム例の場合は無名関数内で名前のある関数ただ1つを 呼んでいるだけなので、
document.addEventListener("DOMContentLoaded", CountDown, false);
と書いても効果は変わらない。