2019年度の新入社員の内海です。
WEBサービス開発グループに所属しており、今現在OJTの最中です。今回はOJT研修中の業務で陥ったDateクラスの罠について記事を書こうと思います。Dateクラスは日付や日時を取得できることから、あらゆるサービスで活用される場面は多いと思います。業務ではNode.js (サーバーサイトのJavaScript実行環境) を使ってコードを書いたのですが、JavaScriptが動的型付け言語であることを忘れていたために生じた間違いや気づきを紹介したいと思います。
そもそも、動的型付け言語とは??
プログラム言語では2種類の変数や関数を扱うタイプが存在し、それが動的型付け言語と静的型付け言語です。
静的型付け言語の特徴
- 静的型付けは変数や関数に型をあらかじめ定義しておき、定義した型以外のデータはその変数では扱うことができません。
動的型付け言語の特徴
- 動的型付けはプログラムを書くときに変数や関数に何が入ってくるかというのが特に決まっていない形を指します。
昨日の日付の取得をしたい場合 (失敗例)
業務の中で、継続的に昨日の日付を取得するようなプログラムを書くことになったので以下の手順で昨日の日付を取得しました。
- Dateインスタンスを生成
-
変数yearにgetFullYear()メソッドで年を取得
-
変数monthに(“0″+(d.getMonth() + 1)).slice(-2)で月を取得
-
変数dayに(“0″+d.getDate()).slice(-2)で日を取得
- day-1をして昨日の日付を取得
- それぞれの変数を結合して昨日の年月日を取得
1 2 3 4 5 6 |
const d = new Date(); const year = d.getFullYear(); const month = (("0"+(d.getMonth() + 1)).slice(-2)); const day = (("0"+d.getDate()).slice(-2)); const today = (year + month + day); const yesterday = (year + month + day-1); |
しかし、このコードには問題があります。
6行目のday-1に注目してみてください。
先輩から指摘されるまでは全く気づきもしなかったのですが、このままでは○○月01日の時の昨日の日付は○○月00日となってしまいます。
理由はJavaScriptが動的型付け言語で暗黙の型変換によりNumber型になるからです!!
今回の場合は1がNumber型なので、引き算をしたことによって自動的にNumber型にキャストされていたわけです。
ただ-1すれば昨日になる!と安易に考えていました……
昨日の日付の取得をしたい場合 (成功例)
そこで、どうしたら昨日の日付が上手く取れるのかを調べました。
結論から言うと、以下のコードで昨日の値が取れました!
1 2 3 4 |
const d = new Date(); d.setDate(d.getDate() -1); const yesterday = d.getFullYear() + ("0" + (d.getMonth()+1)).slice(-2) + ("0" + d.getDate()).slice(-2); document.write(yesterday); |
解説すると、2行目のsetDate()メソッドにgetDate()-1という整数を入れています。
setDate()メソッドは、引数が月の日付の範囲外の値の場合、それに応じてsetDate()がDateオブジェクトを更新します。
ex ) 引数に0を与えた場合、日付は前月の最終日に設定される。
これで、○○月00日とはならずに、前月の最終日の日付が取れるようになります!
感想
今回は実際の業務で陥ったJavaScriptの暗黙の型変換の罠について紹介しました。動的型付け言語は型宣言が必要ないというメリットがある反面、型の不整合に気づくことができないというデメリットがあります。私は型の不整合に気づくことができずに今回のようなミスをしました。
今後、動的型付け言語でコードを書く際には変数の型を頭の片隅で意識してプログラムを組もうと思います。