比較 JavaScript 日期對象也能踩坑?漲姿勢了
直覺上,兩個相同的日期之間比較應(yīng)該是相等的,然而結(jié)果并不是這樣:
- const d1 = new Date('2019-06-01');
- const d2 = new Date('2018-06-01');
- const d3 = new Date('2019-06-01');
- d1 === d3; // false
- d1 == d3; // false
可以看到,無論用===還是==,結(jié)果都是false。細(xì)想也不奇怪,畢竟是兩個獨(dú)立的 JS 對象,并不是基本數(shù)據(jù)類型的變量。那該怎么判斷日期是否相等呢?
可以用toString()或者valueOf()。日期對象的toString()方法將日期轉(zhuǎn)成 ISO 日期字符串形式,而valueOf() 方法則將日期轉(zhuǎn)成毫秒數(shù)字形式的時間戳。
- const d1 = new Date('2019-06-01');
- const d2 = new Date('2018-06-01');
- const d3 = new Date('2019-06-01');
- // Sat Jun 01 2019 08:00:00 GMT+0800 (中國標(biāo)準(zhǔn)時間)
- d1.toString();
- d1.valueOf(); // 1559347200000
- d1.toString() === d2.toString(); // false
- d1.toString() === d3.toString(); // true
- d1.valueOf() === d2.valueOf(); // false
- d1.valueOf() === d3.valueOf(); // true
有意思的是,雖然== 和 === 不能用來比較日期對象,< 和> 卻可以:
- d1 < d2; // false
- d1 < d3; // false
- d2 < d1; // true
因此,要判斷日期a是否在日期 b之前,只要判斷a < b是否為true。另外,日期之間還能用-操作符相減,返回毫秒差值。
- const d1 = new Date('2019-06-01');
- const d2 = new Date('2018-06-01');
- const d3 = new Date('2019-06-01');
- d1 - d3; // 0
- d1 - d2; // 1 年的毫秒數(shù), 1000 * 60 * 60 * 24 * 365
也就是說,你可以用a - b 結(jié)果的正負(fù)來判斷兩個日期的先后。
數(shù)組排序的坑
日期對象數(shù)組排序的結(jié)果很可能出乎意料。比如下面這個排序:
- const d1 = new Date('2017-06-01');
- const d2 = new Date('2018-06-01');
- const d3 = new Date('2019-06-01');
- [d2, d1, d3].sort(); // [d2, d3, d1]
按理說從小到大排序應(yīng)該是[d1, d2, d3],結(jié)果很意外。這是為什么呢?原來,JavaScript 數(shù)組的sort方法默認(rèn)是比較元素的字符串形式。因此,上面的sort實(shí)際上是基于下面的結(jié)果來排序的:
- [ 'Fri Jun 01 2018 08:00:00 GMT+0800 (中國標(biāo)準(zhǔn)時間)',
- 'Sat Jun 01 2019 08:00:00 GMT+0800 (中國標(biāo)準(zhǔn)時間)',
- 'Thu Jun 01 2017 08:00:00 GMT+0800 (中國標(biāo)準(zhǔn)時間)' ]
怎么解決這個問題?很簡單,傳一個自定義的排序函數(shù)compare()給sort()方法。這個compare()函數(shù)的返回值確定了兩個元素的大小(先后順序):
- 0 表示 a 和b 相等
- 正值表示 a > b,也就是a在b后面
- 負(fù)值表示 a < b,也就是a在b前面
由于 JavaScript 日期對象可以直接相減,那這個比較函數(shù)就很簡單了:
- const d1 = new Date('2017-06-01');
- const d2 = new Date('2018-06-01');
- const d3 = new Date('2019-06-01');
- [d2, d1, d3].sort((a, b) => a - b); // [d1, d2, d3]
下次碰到數(shù)組數(shù)組默認(rèn)排序出現(xiàn)這樣的結(jié)果你也就不感到奇怪了:
- const a = [1, 4, 3, 12];
- a.sort(); // [1, 12, 3, 4]
所以為了防止出現(xiàn) Bug,應(yīng)該傳入自定義排序函數(shù)。