ゆるおたノート

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); // #NaNってなんなん?
  // Process time: 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); // これもOK
  // directFinish time: Tue May 21 2019 01:34:46 GMT+0900 (JST)

  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')); // ok.
  // 2019/05/21 02:01:35.304
  
  var finish = new Date;
  Logger.log(Moment.moment(finish).format('YYYY/MM/DD hh:mm:ss.SSS')); // ok.
  // 2019/05/21 02:01:35.307

  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

  Logger.log(typeof Moment.moment(time));
  // object

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

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

しかも、momentオブジェクトはnumber型でもないし変換前後で型が変わるんですね!?
最終的にMoment.jsで取得するつもりだった…あぶなー。

でも…

new Dateしてもnumber型のままなら計算できるはずなんだけどな…
じーっ…(元のコードを眺める)

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

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

  /* ~以下略~ */

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

今度こそ!!

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

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用語辞典