スマフォアプリ作成34:処理時間の計測方法修正とクロージャ | Hello, Stupid World!

Hello, Stupid World!

いろいろとメモ代わりに書いていきます。

前回作った計測用のtimerオブジェクトですが、やはり前回の構造では
使いづらいです・・・
別メソッド内にstartとstopが分かれても簡単に使えるようにと思ったのですが
そうする事でstartとstopの順番を完全に覚えていないと使えないものに
なってしまいました。
(同一メソッド内にstartも無く、引数でそのような変数も渡ってこなければ
startを事前に呼んでいるという事がすぐに分からないので覚えておくしかない)

そこで下記のように修正しました。

[common.js]

//計測開始
model.timer.start = function(){
 var startTime;

 startTime = new Date();
 //計測終了とともに時間を返す
 return function(){
  if (startTime === undefined) {
   return undefined;
  }
  var endTime = new Date();
  var diffTime = endTime - startTime;
  startTime = undefined;
  return diffTime;
 };
}


[解説]
個々の部分は前回と同一なのですが、クロージャになっています。
このような形にした事で、startで帰ってきた値(関数)を実行する事で
処理時間を取得する事ができるようになります。
startとstopを別々の関数で実行したければ引数で渡してやって下さい。

クロージャ自身の説明は当ブログではしてなかったはずなので
説明します。

クロージャはシンプルなオブジェクトであり、関数と変数を関連付けて
保持する事ができるものです。
上記で言うと、return functionで関数自体を返していますが、
その関数とstartTimeが関連付けられているという事です。

model.timer.startが呼ばれると、内部でstatTimeに値が設定され、
戻り値として関数が返されます。
この時にstartTimeは関数と関連づいている為、値が初期化されずに
保持されます。
その為、戻り値として返された関数を呼んだ場合に内部でstartTimeが
使用できるという事です。

この時のstartTimeのような変数をレキシカル変数と呼びます。
グローバル変数のようにどこから使える訳でなく、ローカル変数のように
関数が終了した後に破棄される訳でもない変数です。

もっと分かりやすい例で言えば、こんな感じでしょうか。

[例]
test = function() {
 var i ;
 return function() {
  return i++ ;
 } ;


使い方は
var inc = test() ;
console.log(inc()) ;
console.log(inc());
console.log(inc());

こうする事で順に0, 1, 2と表示されます。
i というプロパティとインクリメントするメソッドを持っているオブジェクトと
考えると理解しやすいのではないでしょうか。
スクリプト系ではクロージャは一般的なので理解しておくと良いと思います。