1
1

More than 1 year has passed since last update.

JavaScriptのジェネレーター関数で二つのDateオブジェクトの期間に月ごとの反復処理を施す方法

Posted at

はいさい!オースティンやいびーん!んながんじゅーやいびーみ?

概要

JavaScriptのジェネレーター関数を使ってDateオブジェクトの期間を月ごとの期間にして繰り返し処理を行う方法を紹介します。

ジェネレーター関数について

JavaScript開発者の多くはJavaScriptのジェネレーター関数を必要だと感じたことがないのではないでしょうか?

実際、ジェネレーターを使わずにやっていても優秀なJavaScript開発者としてやっていけるのだと思います。

しかし、ジェネレーター関数を自分のコーディング道具箱に加えると、時々助かることがあります。

ジェネレータ関数は、for...each構文で使えるオブジェクトを返してくれる関数です。

つまり、半数処理プロトコルのオブジェクトを返す関数です。

半数処理プロトコルのオブジェクトで代表的な物をいえばArrayがもっとも一般に知れているかと思います。

そのArrayと同じような処理ができるオブジェクトを作ってくれるのは、Generatorなのです。

今回は、二つのDateオブジェクトから成る期間の月ごと反復処理を、Generatorを使って行う方法を紹介します。

ジェネレーター関数の定義方法

ジェネレーター関数は以下のように定義します。

function* myGen(arg) {
  yield "cake";
  yield "is";
  yield "yummy";
  yield arg;
}

functionの後に*がついているものはジェネレーター関数になります。yieldという不思議な単語が出てきますが、これは通常関数のreturnだと考えればいいです。

上記のジェネレーター関数を試しにfor...eachで反復処理してみると以下のような結果になります。

const myIterator = myGen(47);

for (const result of myIterator) {
  console.log(result);
}

スクリーンショット 2022-11-12 9.24.59.png

このように簡単にジェネレーター関数が使えます。

ジェネレーター関数の中にwhile構文も、for...each構文も使えるので、yieldごとになんらかの処理を施してから返すことができます。

今回の記事では触れませんが、非同期処理のジェネレーター関数も作れます。

Dateオブジェクトの月ごと反復処理

あまり時間がないので:sweat_smile: 単刀直入に解決法を紹介します。

export function* generateMonthlyInterval(start: Date, end: Date) {
  const startYear = start.getFullYear();
  const startMonth = start.getMonth();
  const endYear = end.getFullYear();
  const endMonth = end.getMonth();
  if (startYear > endYear) throw Error("start year must be less than end year!");
  if (startMonth > endMonth) throw Error("Start month must be less than end month!");
  let currentMonth = startMonth;
  let currentYear = startYear;

  while (currentYear < endYear || currentMonth <= endMonth) {
    const yieldDate = new Date()
    yieldDate.setFullYear(currentYear);
    yieldDate.setMonth(currentMonth);
    yield yieldDate;
    if (currentMonth === 11) {
      currentMonth = 0;
      currentYear++;
    } else {
      currentMonth++;
    }
  }
}

これをJavaScriptにコンパイルして以下のようなコードでテストします。

const interval = generateMonthlyInterval(new Date("2021/10/1"), new Date("2022/11/12"));

let months = 0;
for (const month of interval) {
  console.log(month);
  months++;
}

console.log("total months: ", months);

すると以下のように、開始と終了のDateオブジェクトの間の月々の処理ができます。

スクリーンショット 2022-11-12 9.31.33.png

まとめ

ジェネレーター関数を少し紹介してまいりましたがいかがでしょうか?

Python開発者なら、ジェネレーター関数が日常的に活躍するかと思いますが、JavaScriptでジェネレーターを使う場面はそんなにない気がします。

無闇に使う必要はないのですが、ジェネレーター関数でより簡潔に解決できる課題があるときに、この道具をぜひ活用していただければと思います。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1