JavaScriptの罠まとめ
― Date の月が +1 される問題から学ぶ ―
JavaScript には、知らないと普通に事故る仕様がいくつもあります。
歴史的な事情や後方互換の結果なので仕方ない部分もありますが、
実務では「ハマる前に知っておきたい」ものばかりです。
この記事では、実務で一度は踏む罠を中心に、
短いコード例付きでまとめました。
1. Date の月 (month) が 0 始まり問題
JavaScript の Date コンストラクタは、**月だけ 0 始まり(0〜11)**です。
const d = new Date(2025, 0, 10); // 2025年01月10日
console.log(d.getMonth()); // 0
これを知らずに「1月だから 1 を入れよう」とすると……
const d = new Date(2025, 1, 10);
console.log(d); // 2025-02-10T...
2月になります。
(1 → February)
対策
- 日付ライブラリを使う
-
dayjs,date-fns,luxon
-
-
Dateを使うなら、月を-1する関数を用意する必要があります
2. new Date("YYYY-MM-DD") は UTC 扱いになる
一見ローカル日付に見えますが、
ISO形式の文字列は必ず UTC として解釈されます。
console.log(new Date("2025-01-01"));
// → 2024-12-31T15:00:00.000Z(日本では前日の深夜)
対策
ローカル日付として扱いたい場合は / 区切りを使う。
new Date("2025/01/01"); // ローカル日付として解釈
3. 0.1 + 0.2 !== 0.3
JavaScript の number は IEEE754 の倍精度浮動小数です。
そのため、完全に正確な小数計算はできません。
0.1 + 0.2 === 0.3; // false
対策
-
Math.round()などで桁を丸める - 金額計算などは
decimal.js/big.jsを使う
4. typeof null === "object"
有名な 歴史的バグです。
typeof null; // "object"
typeof だけで判定すると、
null チェック漏れの原因になります。
5. "5" - 1 === 4 なのに "5" + 1 === "51"
原因は **暗黙的な型変換(coercion)**です。
"5" - 1; // 4
"5" + 1; // "51"
対策
- 数値化は必ず明示的に行う
Number(value);
-
"use strict"+ TypeScript の導入
6. [] == ![] が true になる
[] == ![]; // true
JavaScript の 抽象等価(==)はカオスです。
正直、挙動を追いかける価値はありません。
7. for...in は配列用ではない
for...in は オブジェクト用です。
const arr = [10, 20, 30];
for (let i in arr) {
console.log(i);
}
一見問題なさそうですが、
- インデックス順が保証されない
-
prototypeのキーも拾う可能性がある
対策
配列には以下を使います。
for...offorEachmap
8. parseInt の罠(切り捨て & 基数問題)
parseInt("10px"); // 10
parseInt("010"); // 古い環境では 8進数扱いの可能性
対策
必ず基数を指定する。
parseInt("010", 10);
9. == は使うな。基本すべて ===
0 == ""; // true
0 == "0"; // true
"" == "0"; // false
「
==の挙動をすべて暗記している人だけ使っていい」
それくらい危険です。
対策
-
==を使わない - ESLint で禁止する
10. 配列の「穴」は map や forEach でスキップされる
const arr = [1, , 3];
arr.map(x => x); // [1, , 3]
真ん中は実行されません。
地味ですが、デバッグがかなりつらいポイントです。
11. NaN は何とも等しくない
NaN === NaN; // false
対策
Number.isNaN(value);
12. マイナスゼロ (-0) が存在する
1 / -0; // -Infinity
表示上は区別できませんが、
内部的には 0 と -0 は別物です。
まとめ
JavaScript は、歴史的仕様と後方互換の影響で
直感に反する挙動が本当に多い言語です。
実務では、次のルールを守るだけでも事故はかなり減ります。
-
Dateは基本そのまま使わず、日付ライブラリを使う - 暗黙の型変換に頼らない(
===を使う) -
parseIntには必ず基数を指定 - 配列に
for...inを使わない -
new Date("YYYY-MM-DD")を使わない
特に 「Date の月だけ 0 始まり」 は
全エンジニアが一度はやらかすポイントなので、
仕様として早めに身体に染み込ませておきたいところです。