【问题标题】:Javascript Variable Reference Bug?Javascript 变量参考错误?
【发布时间】:2021-10-26 23:54:56
【问题描述】:

我遇到了一个奇怪的问题,我认为这是 Javascript 引用变量的方式。我正在从事的项目是 Typescript,但这个功能来自 vanilla Javascript。

我在代码中进一步设置了一个对象 all_obj。

以下代码:

all = [];
data = [];

console.log(all_obj);

输出:

{
  "1593561600000": {
    "date": 1593561600000,
    "volume": 24463,
    "value": 165049285,
    "rank": 0
  },
  "1596240000000": {
    "date": 1596240000000,
    "volume": 24366,
    "value": 158841976,
    "rank": 0
  },
  "1604188800000": {
    "date": 1604188800000,
    "volume": 30034,
    "value": 196655815,
    "rank": 0
  },
  This goes on 9 more times with similar objects
}

这按预期工作。

但是,以下代码以某种方式记录了完全不同的内容:

let all = [];
let data = [];

console.log(all_obj);

for (let key of Object.keys(all_obj)) {
  all.push(all_obj[key]);
}

this.data.push(
  {
    brand: 'all_aggregated',
    datapoints: [...all],
  },
  {
    brand: 'all_mean',
    datapoints: [...all].map((dp: brand_datapoint) => {
      dp.value = +(dp.value / dp.volume).toFixed(2);

      return dp;
    }),
  }
);

它会记录:

{
  "1593561600000": {
    "date": 1593561600000,
    "volume": 24463,
    "value": 6746.89,
    "rank": 0
  },
  "1596240000000": {
    "date": 1596240000000,
    "volume": 24366,
    "value": 6519,
    "rank": 0
  },
  "1604188800000": {
    "date": 1604188800000,
    "volume": 30034,
    "value": 6547.77,
    "rank": 0
  },
  9 more like this
}

如您所见,在第二个示例中。 all_obj 的孩子中的“价值”现在是数千,而不是数亿。此外,它被格式化为 2 位小数。这可能是我在第二个代码示例末尾的这一行中所做的格式:

dp.value = +(dp.value / dp.volume).toFixed(2);

到底是如何改变传播备份代码的值???

尤其是通过 [...all]

这是在 Angular 项目中运行的。我已经消除了臃肿,如果您需要更多信息当然可以询问,但我不想在这里粘贴 300 行代码:)

我已经为此奋斗了大约 6 个小时,并以大约 15 种不同的方式完全重写了相同的代码。所以我完全不知道是什么原因造成的。

解决方案! 问题不在于数据正在传播回 all_obj,而是在粉红色箭头中设置了值,并且在红色箭头中被拾取,因为它们只是在引用它。我认为 [...all] 会修复它,但这只是构建一个具有相同引用的新数组。

【问题讨论】:

    标签: javascript arrays angular typescript


    【解决方案1】:

    问题是您正在编辑您开始使用的同一对象上的value。

    当您执行all.push(all_obj[key]); 时,您正在用一堆对all_obj 中内部对象的引用填充all。由于这些只是引用,因此与它们交互会更改相同的对象,就像all_obj 中的对象一样。因此,当您设置值 dp.value = 时,它正在“传播备份代码”,因为它与 all_obj 内部的对象相同。

    由于您想对新对象进行这些更改只是出于格式化原因,您应该制作该对象的副本并仅在其中编辑值。由于数据点看起来很简单,只有简单的数字作为属性,您可以轻松地复制

    dp = {...dp};
    

    您应该在更改值之前执行此操作。

    您可能认为不需要这样做,因为[...all]。但是,这只会复制all 列表本身,而不是所有内容。所以基本上它是一个“新列表”,其中包含对所有相同对象的所有相同引用。

    您可能对Is JavaScript a pass-by-reference or pass-by-value language?感兴趣

    编辑:

    再看一遍,在构建all 数组时,制作正确的版权可能会更好/更干净。所以不要这样做

    all.push(all_obj[key]);
    

    你可以的

    all.push({...all_obj[key]});
    

    那么您无需担心在操作点以进行格式化或显示时更改原始数据。

    【讨论】:

    • 你是明星。我正在做 all_obj = {...all_obj},然后我想也许这不会重新声明它,而只是将对其子项的引用放在一个新对象中。所以我在做 JSON.parse(JSON.stringify()) 等。我想知道为什么它不起作用。但一直都是重制dp的问题。谢谢!
    猜你喜欢
    • 2015-02-17
    • 1970-01-01
    • 2012-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-10
    相关资源
    最近更新 更多