为什么这个简单的 moment.js 逻辑会导致无限循环?

Why does this simple moment.js logic cause an infinite loop?

这段代码创建了一个无限循环。

|将 <= 更改为 < 不会创建无限循环。

var s_date = "2020-05-07";
var e_date = "2020-12-31";

for (
  var i = 0;
  Number(moment(s_date).add(i, "M").format("M")) <=
  Number(moment(e_date).format("M"));
  i++
) {
  var month = moment(s_date).add(i, "M").format("MMM");
  console.log(month, moment(e_date).format("MMM"));
}

输出:

May Dec
Jun Dec
Jul Dec
Aug Dec
Sep Dec
Oct Dec
Nov Dec
Dec Dec
Jan Dec
...

Number(moment(e_date).format("M")) 是 11.

Number(moment(s_date).add(i, "M").format("M")) 在 [0, 11] 范围内。

x <= 11 对 [0, 11] 中的所有 x 都成立。

Number(moment(s_date).add(i, "M").format("M")) <= Number(moment(e_date).format("M"))

总是正确的。

就像

for (let i = 0; (5 + i) % 12 <= 11; i++) // infinite loop

for (let i = 0; (5 + i) % 12 < 11; i++) // leaves loop for i == 6

更深层次的想法是,日期是数量,而格式化字符串不是,即使被强制转换为数字。使用diff衡量数量差异,分解循环不变代码更高效可读

const s_date = "2020-05-07";
const e_date = "2020-12-31";

let mStart = moment(s_date);
let mEnd = moment(e_date);

for (
  let mDate = mStart.clone();
  mEnd.diff(mDate, "M") > 0;
  mDate.add(1, "M")
) {
  console.log(mDate.format("MMM"), mEnd.format("MMM"));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>