【问题标题】:Array Push 'Different Info' Results in Pushing Same First Iteration For Every Iteration数组推送“不同信息”导致每次迭代都推送相同的第一次迭代
【发布时间】:2019-12-18 15:43:01
【问题描述】:

我试图每天 3 次通知用户他的药物,所以我创建了:

let timesPerDay = []

const today = moment();
//not working
for (let i = 0; i < 3; i++) {
  timesPerDay.push(today.add(8 * i, "hour"));
}
//working normally
for (let i = 0; i < 3; i++) {
  console.log(today.add(8 * i, "hour"));
}

console.log(timesPerDay)
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"&gt;&lt;/script&gt;

但是有一个奇怪的错误,当推送到数组时,它保存每次迭代的第一个日期而不是每次都增加 8 小时,这太奇怪了!

Array.push 是如何工作的?

JavaScript 创建数组的速度是否太快,所以第一个循环不工作但第二个循环工作?

代码笔: https://codepen.io/microsmsm-the-flexboxer/pen/BaypYVO

编辑:

答案不起作用后我正在使用的相同片段

https://codepen.io/microsmsm-the-flexboxer/pen/KKwaoeM

【问题讨论】:

  • 绝对不是“怪异”。它按预期工作,因为.add() “通过增加时间来改变原始时刻。”
  • @Andreas 但我在第一次迭代时加了 0 小时,在第二次迭代时加了 8 小时,在最后一次迭代时加了 16 小时,为什么数组会产生相同的值?
  • 我希望所有日期实际上都相等,即最后一个突变的值。每次迭代都在改变同一个实例
  • 但为什么第二个循环工作正常?
  • 第二个循环似乎正常工作,因为它在每个间隔而不是在结束时输出。它仍然应该是 startdate +0 在第一 + 0 + 8 在第二和 + 0 + 8 + 16 在结束

标签: javascript arrays angular momentjs pass-by-rvalue-reference


【解决方案1】:

逐步引导您完成代码:

let timesPerDay = [] // create an array

const today = moment(); // create a moment object

for (let i = 0; i < 3; i++) {
  // add hours to moment object
  // push a reference to that moment object into your array
  // it's always a reference to the SAME moment object, so the same object is referenced in your array multiple times
  // mutations to that object will show everywhere it is referenced
  timesPerDay.push(today.add(8 * i, "hour")); 
}

for (let i = 0; i < 3; i++) {
  // add hours to same moment object
  // log the string representation of that object AT EACH ITERATION
  // once transformed to a string, the string representation will not change as it is no longer part of the object
  console.log(today.add(8 * i, "hour"));
}

console.log(timesPerDay) // log string representation of your array, which is just 3 references to the same object

【讨论】:

  • console.log 是否因为它是一个又一个同步日志而打破了引用?
  • console.log 调用 toString 将对象转换为可以记录的字符串。该字符串是从对象上的函数输出的,它不再是您正在变异的对象
  • 那么如何通过在数组中生成 3 个不同的值来解决这个问题?
  • 在每次迭代时创建一个新的时刻对象
  • 我试过了还是同样的问题,请查看截图
【解决方案2】:

这是因为您使用相同的时刻对象来推动 所以这应该会有所帮助

let timesPerDay = []

for (let i = 0; i < 3; i++) {
  timesPerDay.push(moment().add(8*i,"hour"));
}

for (let i = 0; i < 3; i++) {
  console.log(moment().add(8*i,"hour"));
}

console.log(timesPerDay)

【讨论】:

  • 感谢回答,但为什么在第二个循环中可以正常工作?
【解决方案3】:

由于 momentjs .add 正在改变 today 变量,所有日期都将相同(等于开始日期 + 0 + 8 + 16 小时),因为您一直在推送相同的参考。

您必须复制日期才能重新开始。

const today = moment()
console.log(`Today: ${today}`)
// Today: Wed Dec 18 2019 17:14:11 GMT+0100
// Loop 0: Wed Dec 18 2019 17:14:11 GMT+0100
// Loop 1: Thu Dec 19 2019 01:14:11 GMT+0100
// Loop 2: Thu Dec 19 2019 09:14:11 GMT+0100
const times = [0, 1, 2].map(offset => {
    const date = moment(today) // clone
    date.add(8*offset,"hour")
    console.log(`Loop ${offset}: ${date}`)
    return date
})

编辑:不是 + 8 + 16 + 24 而是 0 + 8 + 16

编辑 2:证明 console.log 的第二次迭代没有输出 OP 想要的内容:

let timesPerDay = []

const today = moment();
console.log(`today: ${today}`)

// today: Wed Dec 18 2019 17:03:02 GMT+0100
// Loop 0: Wed Dec 18 2019 17:03:02 GMT+0100
// Loop 1: Thu Dec 19 2019 01:03:02 GMT+0100
// Loop 2: Thu Dec 19 2019 17:03:02 GMT+0100
// Last loop is 24 hours later than the initial date!
for (let i = 0; i < 3; i++) {
  // Mutates your start date
   const newDate = today.add(8*i,"hour");
   timesPerDay.push(newDate);
   console.log(`Loop ${i}: ${newDate}`);
}

console.log(timesPerDay)

【讨论】:

  • 答案对我不起作用我尝试“克隆对象”但在数组中仍然有相同的结果
  • 答案是有效的。我添加了与“证明”相同的控制台日志记录。提供的屏幕截图是与我的答案不同的代码。更新您的 sn-p 而不是屏幕截图。
  • 这是你想要的结果,不是吗?如果你把日期串起来,你会得到你所期望的。我认为您关注的是初始日期的 _i 属性,而 _d 属性是修改后的属性。 _i 和 _d 的作用超出了我的范围,但是当您将日期字符串化时,会生成正确的输出。
  • 关于_i和_id的说明可以看here
猜你喜欢
  • 1970-01-01
  • 2020-07-28
  • 1970-01-01
  • 2014-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-04
  • 1970-01-01
相关资源
最近更新 更多