ゆるおたノート

Tomorrow is another day.

【Google Apps Script】クラスの練習をしていたらハマった話。

今日は簡単にメモします。

クラスの練習でメソッドを呼び出してみたら、何度やってもなぜかreturnしてほしい値ではなく「関数の中身」が出力されてしまうっていう時は…

メソッドの後ろに()をつけるのを忘れているかもしれません。

サンプル

今回は、Timerクラス*1の作成に挑戦しました。

クラス

/**
 * 実行時間計測用のクラス
 * ※あらかじめ使用するプロジェクトにMoment.jsライブラリを導入しておくこと!
 * プロジェクトキー:MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48
 *
 * @param {sheet} ログに使用するシート
 */
var Timer = function(logSheet) {
  /* 作成中 */
  this.logSheet = logSheet;
}

Timer.prototype = {
  start : function() {
    return new Date;
  },

  finish : function() {
    return new Date;
  }
};

メイン

処理時間を見たかったのですが、思ったとおりに計算ができていません。

function testTimer() {
  var Timer = new Timer();

  var start = Timer.start;
  Logger.log('\n' + 'start time: ' + start);
  /*
    start time: 
    function () {
        return new Date();
    }
   */
  // (値が欲しいのに関数の中身が出てるな…???)
  
  var finish = Timer.finish;
  Logger.log('\n' + 'finish time: ' + finish);
  /*
    finish time: 
    function () {
        return new Date();
    }
  */
  // (値が欲しいんだってば…)

  var time   = finish - start;
  Logger.log('\n' + 'Process time: ' + time); // 
  /* Process time: NaN */
  // (#NaNってなんなん?)
}

そもそも計算できない値…?

そんなわけない。

function getTime() {
  var directStart  = new Date;
  Logger.log('\n' + 'directStart time: ' + directStart);
  // directStart time: Tue May 21 2019 01:34:46 GMT+0900 (JST)
  // (こっち↑は値を返してくれてる。)

  var directFinish = new Date;
  Logger.log('\n' + 'directFinish time: ' + directFinish);
  // directFinish time: Tue May 21 2019 01:34:46 GMT+0900 (JST)
  // (これ↑もOK。)

  Logger.log((directStart - directFinish).toFixed(3));
  // 3.000
  // (計算もできてる。)
}

こちらは問題なさそう。

じゃあMomentは…?

momentオブジェクト同士では計算できないようです*2…うーむ…

function getMoment() {
  var start = new Date;
  Logger.log(Moment.moment(start).format('YYYY/MM/DD hh:mm:ss.SSS'));
  // 2019/05/21 02:01:35.304
  // (ok.)
  
  var finish = new Date;
  Logger.log(Moment.moment(finish).format('YYYY/MM/DD hh:mm:ss.SSS'));
  // 2019/05/21 02:01:35.307
  // (ok.)

  var time = finish - start;
  Logger.log(time.toFixed(3));
  // 3.000
  // (あ、これ↑は変換前どうしだから「ミリ秒」か…)

  var timeMoment = Moment.moment(time).format('YYYY/MM/DD hh:mm:ss.SSS');
  Logger.log(timeMoment);
  // 1970/01/01 09:00:00.003
  // (ん???これ↑はシリアル値かな…???)

  // これならどうだ!
  var startMoment = Moment.moment(start).format('YYYY/MM/DD hh:mm:ss.SSS');
  var finishMoment = Moment.moment(finish).format('YYYY/MM/DD hh:mm:ss.SSS');
  Logger.log(finishMoment - startMoment);
  // NaN
  // (だから#NaNって(略)
}

ちなみに、(大きい処理はあまりしませんが)ほかにも私が何回か試した限りでは、処理時間はMomentライブラリ経由でもミリ秒単位で違うくらいのようですね。これなら安心して使える…

そういえば型はどうなってる…?

typeof演算子*3で型を出力してみます。

function getType() {
  var time = new Date;
  Logger.log(typeof time); // number
}

new Dateしただけならnumber型じゃないですか…
それなら計算できるでしょ…???

じゃあMoment使うとどうなる…?

Logger.log(typeof Moment.moment(time)); // object
Logger.log(typeof Moment.moment(time).format('YYYY/MM/DD hh:mm:ss.SSS')); // string

あれ、momentオブジェクトは変換前後で型が変わるんですね!?
しかも変換後はnumber型じゃなくてstring型!?

最終的にMomentライブラリで計算して出力するつもりだった…あっぶなー。

じゃあ問題はどこ???

型は問題ないとして…

momentオブジェクトのことは一旦置いといて、new Dateしてもnumber型のままなら計算できるはずなんだけどなぁ…

じーっ…(元のコードを眺める)

function testTimer() {
  var Timer = new Timer();

  var start  = Timer.start; // ← んんん!?

  /* ~以下略~ */

あれ、なにか忘れてる…!?

あれ???

startメソッドに()が抜けていました。結局たいぽ…

var start  = Timer.start(); // ← これ

本日の答え。

というわけで、正しいTimerクラスの使い方はこんな感じです。

function testTimer() {
  var Timer2 = new Timer;

  var start  = Timer2.start(); // ← '()'を追加
  Logger.log('\n' + 'start time: ' + start);
  // start time: Tue May 21 2019 02:31:41 GMT+0900 (JST)
  
  var finish = Timer2.finish(); // ← '()'を追加
  Logger.log('\n' + 'finish time: ' + finish);
  // finish time: Tue May 21 2019 02:31:41 GMT+0900 (JST)  

  var time   = finish - start;
  Logger.log('\n' + 'Process time: ' + time.toFixed(3));
  // Process time: 2.000
}

これで、ひとまず時間の計測は出来るようになりました。

めでたしめでたし。

参照

*1: こちらを参考にさせていただきました。 tonari-it.com

*2: 別途メソッドを使用するようです。これをクラスに実装しよう。
tonari-it.com

*3: 詳しくは、以下(外部サイト)をご参照ください。
qiita.com
developer.mozilla.org
オペランド (operand)とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典