【问题标题】:forEach loop doesn't update an Object valueforEach 循环不会更新 Object 值
【发布时间】:2019-10-10 04:44:12
【问题描述】:

我正在尝试执行一个循环并使用每个循环值更新一个对象属性,但发生了一些意想不到的事情:

第一个console.log 打印按预期更新的day 对象属性。然而,第二个打印完整对象,显示 day 属性,其值为 final forEach 值。

示例: data.days = [ 5, 6 ]

第一个循环打印:

newData.date: 5
{prop1: x, prop2: x...., date: 6}

第二次循环打印:

newData.date: 6
{prop1: x, prop2: x...., date: 6}

这是我的代码:

data.days.forEach(day => {
    let newData;
    newData = data.data;
    newData.date = day;
    console.log('newData.date: ' + newData.date)
    console.log(newData)
})

我尝试用forEachfor 循环创建newData 变量,但结果相同。

【问题讨论】:

  • data.days = { 5, 6 } 语法无效
  • 正如 Maheer Ali 告诉你的那样:forEach 适用于数组,而 data.days 是 ...
  • newData = data.data 是通过引用复制的,您实际上是在每个循环上分配相同的对象。这就是为什么你总是在最终循环中得到 last value...
  • data.days 被声明为一个空数组,并且在调用循环之前根据我的需要推送或拼接这些值。事实上,正如您在第一个 console.log 中看到的那样,它在每个循环中打印正确的值

标签: javascript loops foreach


【解决方案1】:

您看到的问题是由于浏览器控制台在您记录对象时没有记录字符串,以提供帮助。相反,它正在记录该对象的实时视图。因此,如果您记录对象然后更新它,您将在控制台中看到更新的版本。但是,当您记录对象的属性时,控制台会将其记录为静态字符串。

你可以在这里看到这个:

字符串只是作为静态字符串记录,但对象被特殊处理,语法突出显示和扩展属性视图等。

这是一个示例,我们记录对象的静态字符串化版本以及对对象的动态引用:

let days = [5, 6];
let newData = {};

days.forEach(day => {
    newData.date = day;
    console.log('newData.date: ' + newData.date);
    console.log(JSON.stringify(newData));
    console.log(newData);
});

这会产生:

【讨论】:

  • 有道理,但现在我有一个新问题:我需要在每个循环中执行一个 post 请求。它会创建一个具有不同日期值的新寄存器,但它会创建与数组长度一样多的寄存器,但都使用最后一个循环值。
  • @KenRamirez 我不确定到底发生了什么,但听起来你可能会遇到发布请求是异步的问题,所以轻微的延迟意味着它正在发送最终版本。如果您在循环中使用JSON.stringify 发送数据会怎样?作为请求过程的一部分,它无论如何都会被字符串化。
【解决方案2】:

您的问题在这里:

...
let newData;
newData = data.data;
...

您不是使用newData 变量创建新对象,而是在每次迭代时将相同的data.data 对象引用到其中。这就是为什么最终的 newData 值将始终是最后一次循环迭代中设置的值。

如果想要为每个循环创建一个新的不同对象,您需要(深度)克隆/复制 data.data 而不仅仅是引用它:

var data = {};
data.data = { prop1: 'x', prop2: 'x' };
data.days = [ 5, 6 ];

data.days.forEach(day => {
    let newData;
    newData = Object.assign({}, data.data); 
    newData.date = day;
    console.log('newData.date: ' + newData.date)
    console.log(newData)
});

注意:Object.assign 对对象进行浅拷贝,如果需要对对象进行深拷贝,则需要借助其他方法。

【讨论】:

    【解决方案3】:

    对象没有forEach 方法(主要用于数组),但您可以使用for (let prop in object) 迭代它们的属性。

    在你的例子中:

    for (let day in data.days) {
        // Do your stuff
    }
    

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in

    【讨论】:

    • 正如我所说,我尝试使用“for”循环,但得到相同的结果。控制台正确显示 for 或 foreach 对象值,甚至更新后的对象属性,但是当我想在更新后打印完整对象时,更新后的属性显示 forEach 的 LAST 值
    • 哦,我想是因为 newData 的值每次循环都会更新但没有保存。您可以在 for 范围之外将其声明为 Array 并将每天的值推入其中。
    【解决方案4】:

    根据 ECMAScript 文档, a link

    在 22.1.3.12 Array.prototype.forEach (callbackfn [ , thisArg ] )

    callbackfn 应该是一个接受三个参数的函数。 forEach 为数组中存在的每个元素按升序调用 callbackfn 一次。 callbackfn 仅对实际存在的数组元素调用;数组的缺失元素不会调用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-02
      • 1970-01-01
      • 2017-02-03
      • 1970-01-01
      • 2014-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多