みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。
GASでGoogleカレンダーの複数の予定をまとめて登録するツールを作成しています。
前回の記事はこちら。
日付関連の処理を関数化してスクリプトをスッキリさせる例についてお伝えしました。
さて、その関数化した関数なのですが、呼び出すときの引数が省略された場合にデフォルトの値を設定するように工夫していたんですね。
今回は、引数が省略された場合には仮引数はどうなってしまうのか、またその際の不都合を回避するためにはどうすべきかについて解説をしていきます。
Google Apps Scriptで関数の引数を省略した場合の挙動とデフォルト値の設定方法についてです。
では、行ってみましょう!
前回のおさらい
前回作成したスクリプトはこちらです。
function createEvents() { const calendar = CalendarApp.getDefaultCalendar(); const values = SpreadsheetApp.getActiveSheet().getDataRange().getValues(); values.shift(); for(const record of values){ const title = record[0]; const date = new Date(record[1]); const time = new Date(record[2]); const delta = new Date(record[3]); const startTime = setTimeDelta(new Date(date), time); const endTime = setTimeDelta(new Date(startTime), time, delta); const option = { description: record[4], location: record[5] } calendar.createEvent(title, startTime, endTime, option); } } /* * 日付のみのDateオブジェクトに与えられた時刻をセットしさらに時間の加算をする * * @param {Date} 日付を表すDateオブジェクト * @param {Date} 時刻を表すDateオブジェクト * @param {Date} 加算する時間を表すDateオブジェクト、デフォルトはnew Date(0,0,0,0,0,0); * @return {Date} 日付をベースに、時刻をセットし、加算する時刻を加算したDateオブジェクト */ function setTimeDelta(date, time, delta){ if(!delta) delta = new Date(0,0,0,0,0,0); date.setHours(time.getHours() + delta.getHours()); date.setMinutes(time.getMinutes() + delta.getMinutes()); return date; }
スプレッドシートに入力してある予定リストをもとに、デフォルトのGoogleカレンダーにイベントを追加していくというものです。
関数createEventsがメインの関数で、その中の日付関連の共通処理を関数化して分離したものが関数setTimeDeltaになります。
引数が省略された場合の仮引数の値
さて、上記のスクリプトですが12,13行目で関数setTimeDeltaをそれぞれ呼び出していますね。
それで、その引数の数に注目をすると
- startTimeを求めるときには、引数が2つ
- endTimeを求めるときには、引数が3つ
となっています。
一方で、関数setTimeDeltaのほうは、その受け皿として仮引数はdate, time, deltaの3つがありますよね。
つまり、startTimeを求めるときには、最後の引数が省略されているわけですが、その仮引数deltaの値ってどうなっちゃってるんですかね?
引数が省略されたら仮引数はundefinedに
試しに、33行目の前に以下のステートメントを挿入して試してみましょう。
console.log(delta);
そうすると、以下のようにログ出力がされます。
そうなんです、GAS(というかJavaScript)では、関数呼び出しのときに引数を与えられていない仮引数の値は「undefined」になるのです。
undefinedというのは「未定義」を表す特殊な値です。
引数のデフォルト値を設定する
このままにしておくと、関数setTimeDelta内の以降のgetHoursメソッドなどでエラーを起こしてしまうので、引数が省略されたときにデフォルト値を設定しておくと良いということになります。
その部分が、以下のif文の処理ということですね。
if(!delta) delta = new Date(0,0,0,0,0,0);
このif文のように、変数自体をif文の条件式に指定した場合は、その変数の値が真偽値に型変換されます。
そして、Dateオブジェクトであればnullまたはundefinedでない限りはtrueの判定になります。
一方で、undefinedはfalseになりますから、その場合にif文の処理が実行され、すべての要素が0であるDateオブジェクトが生成されてdeltaにセットされるということになります。
なぜ引数で与えずにデフォルト値の処理を入れるか
なお、そもそも関数setTimeDeltaへの第3引数を省略せずに「new Date(0,0,0,0,0,0)」を指定する方法もあります。
ですが、多くの場合、指定すべき引数の数は減らせたほうが良いはずです。
例えば、関数setTimeDeltaを第3引数を「new Date(0,0,0,0,0,0)」で何回も使用することがあるとしたら、都度指定するのはどう考えても面倒ですもんね。
デフォルト引数でデフォルト値を設定する
さて、V8ランタイムがサポートされてから、別の解決法が生まれました。
それが「デフォルト引数」です。
デフォルト引数は以下のように設定します。
//処理
}
つまり、仮引数に=記号を使って「引数が与えられなかったときにデフォルトで設定したい値」を記述しておくのです。
これにより、関数setTimeDeltaは以下のように記述することができます。
/* * 日付のみのDateオブジェクトに与えられた時刻をセットしさらに時間の加算をする * * @param {Date} 日付を表すDateオブジェクト * @param {Date} 時刻を表すDateオブジェクト * @param {Date} 加算する時間を表すDateオブジェクト、デフォルトはnew Date(0,0,0,0,0,0); * @return {Date} 日付をベースに、時刻をセットし、加算する時刻を加算したDateオブジェクト */ function setTimeDelta(date, time, delta=new Date(0,0,0,0,0,0)){ date.setHours(time.getHours() + delta.getHours()); date.setMinutes(time.getMinutes() + delta.getMinutes()); return date; }
スッキリ書けるようになりましたね。
まとめ
以上、Google Apps Scriptで関数の引数を省略した場合の挙動とデフォルト値の設定方法についてお伝えしました。
GAS(というかJavaScript)では、関数の引数は省略できること、また省略した場合の仮引数はundefinedになるということですね。
そして、V8ランタイムからデフォルト引数が使えるようになりました!
これで、引数の省略もスマートに実現できますね!