見出し画像

GASでクラス事始め

ノンプロ研でGAS勉強中です。

ただいま絶賛GAS中級講座を受講中で、今週は2回めの講義でテーマは「クラス・ライブラリ」

中級講座は、「GASの開発・保守を楽に&スマートに」がゴールで、その目標達成のためにも今回のテーマは非常に重要。

ただ、クラスってイマイチ使いどころがわからないというのが正直なところで、そんな中でちょっと取っ掛かりをもらえた気がしました。

クラスのカンドコロ?

ノンプロ研のGAS中級講座の第1回ではスコープについて学びました。

そのなかでプロジェクト全体から使用できるグローバルスコープには「むやみにコードを書かないでね」という注意書きがあったにも関わらず、関数を書く度に重複して書くコードはグローバルにあげると楽ちんと調子に乗って書いてました。

そのひとつが、カレンダーやスプレッドシート、メールなど多岐に渡って活躍する日付関連のDateオブジェクト関連の定数です。

経理などの事務仕事関連でよく登場する下記の日付のDateオブジェクトは、毎回書くのは面倒だしな…とグローバルスコープへ。

// 日付に関するグローバル定数(すべてDateオブジェクト)

const now = new Date();
const today = now;

const endThisMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0);
const endNextMonth = new Date(today.getFullYear(), today.getMonth() + 2, 0);
const endLastMonth = new Date(today.getFullYear(), today.getMonth(), 0);

const beginThisMonth = new Date(today.getFullYear(), today.getMonth(), 1);
const beginNextMonth = new Date(today.getFullYear(), today.getMonth() + 1, 1);
const beginLastMonth = new Date(today.getFullYear(), today.getMonth() - 1, 1);

しかし、グローバルスコープのコードは、プロジェクト内のいずれかの関数が実行される度に実行されるということで、使わないケースもあるのに毎回定義するとかもっさりするのかなと思い始めました(メモリ云々の話)。

加えて、上記の定数の宣言だと今月末も先月末も来月末も起点となる日付はかならず today = 今日 という日になります。

いや、今月末とか今というくらいなので今日を起点で良いのですが、起点日を変えて他の日付を取得できれば、より応用が効くのも事実です。

ということで、講義直後にこういう風に書き換えてみました。

// 日付に関するグローバル定数(すべてDateオブジェクト)
const now = new Date();
const today = now;

// カレンダーの色々な日付を生成するクラス
class CalDate {
 constructor(date = today) {
   if (typeof date === 'string') {
     this.date = new Date(date);
   } else {
     this.date = date;
   }
 }
 endThisMonth() {
   return new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0)
 };
 endNextMonth() {
   return new Date(this.date.getFullYear(), this.date.getMonth() + 2, 0)
 };
 endLastMonth() {
   return new Date(this.date.getFullYear(), this.date.getMonth(), 0)
 };
 beginThisMonth() {
   return new Date(this.date.getFullYear(), this.date.getMonth(), 1)
 };
 beginNextMonth() {
   return new Date(this.date.getFullYear(), this.date.getMonth() + 1, 1)
 };
 beginLastMonth() {
   return new Date(this.date.getFullYear(), this.date.getMonth() - 1, 1)
 };
}

これであれば引数に与えた日付オブジェクトを起点日として、様々な日付が取れますし、そのデフォルト引数を今日にしておけば、サクッと今日を起点日にすることも簡単です。

あと、スプレッドシートから日付の文字列を取得してDateオブジェクトに変換したいみたいな場面はちょくちょくありそうなので、引数に渡す値の型が文字列(YYYY/MM/DD)である場合とそれ以外(= Dateオブジェクト)で条件分岐して、直感的に狙った日付を取得できるようにしました。

function myFunction() {
 const date1 = new CalDate().endThisMonth();
 console.log(date1);  // Mon May 31 2021 00:00:00 GMT+0900 (Japan Standard Time)

 const date2 = new CalDate('2021/04/27').endThisMonth();
 console.log(date2);  // Fri Apr 30 2021 00:00:00 GMT+0900 (Japan Standard Time)
}

これで、定数ベタ書きよりも、ちょっとスッキリした気がします。多分メモリの確保も少ないはず。

ただ、そもそも関数でも同じでは?という疑問もあって、そのあたりの切り分けと分析が今後の課題です。

個人的には、calDate()の引数にYYYY/MM/DDの日付の文字列を渡せる部分がハイライト。





この記事が気に入ったらサポートをしてみませんか?