[英]Strange behavior in for-loop in JS/NodeJS
我正在开发一个 NodeJS/VueJS 应用程序,我遇到了一些奇怪的行为,我不确定这是我做错了什么还是其他什么。
我有 2 个 arrays,一个包含活动的对象数组和一个包含与所有活动相关的所有促销活动的对象数组。
此时,每个活动 object 都包含一个名为 promos 的空数组,我想在其中推送每个活动的所有促销活动。
for (var i = 0; i < campaigns.length; i++) {
for (var j = 0; j < campaignsPromo.length; j++) {
if (campaignsPromo.length > 0) {
if (campaigns[i].IDCampaign == campaignsPromo[j].IDCampaign) {
if ((campaignsPromo[j].associated == 1) && (campaignsPromo[j].validated == 1)) {
campaigns[i].promos.push(campaignsPromo[j]);
console.log("Validated Campaign ID " + campaigns[i].IDCampaign);
console.log("Promo ID " + campaignsPromo[j].IDPromo);
} else if ((campaignsPromo[j].associated == 1) && (campaignsPromo[j].validated == 0)) {
campaigns[i].unvalidatedPromos++;
console.log("Unvalidated Campaign ID " + campaigns[i].IDCampaign);
console.log("Promo ID " + campaignsPromo[j].IDPromo);
}
}
} else {
console.log("No promos!");
}
}
}
起初,代码似乎在做它应该做的事情,它检查了我的测试数据集。 然而,最终,所有活动最终都会有相同的促销活动。
Campaigns With No Promos: [{"IDCampaign":7,"campaignName":"dadsadafds","startDate":"2022-02-03","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[]},{"IDCampaign":3,"campaignName":"Tarzan 3","startDate":"2022-02-02","endDate":"2022-02-06","unvalidatedPromos":0,"promos":[]},{"IDCampaign":1,"campaignName":"Tarzan","startDate":"2022-02-01","endDate":"2022-03-01","unvalidatedPromos":0,"promos":[]},{"IDCampaign":2,"campaignName":"Tarzan 2","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[]},{"IDCampaign":4,"campaignName":"Tarzan 4","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[]},{"IDCampaign":5,"campaignName":"Jabe 1","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[]},{"IDCampaign":6,"campaignName":"dadsada","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[]},{"IDCampaign":8,"campaignName":"Black Friday","startDate":"2022-02-01","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[]}]
Validated Campaign ID 1
Promo ID 1119
Unvalidated Campaign ID 1
Promo ID 107
Campaigns With Promos: [{"IDCampaign":7,"campaignName":"dadsadafds","startDate":"2022-02-03","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":3,"campaignName":"Tarzan 3","startDate":"2022-02-02","endDate":"2022-02-06","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":1,"campaignName":"Tarzan","startDate":"2022-02-01","endDate":"2022-03-01","unvalidatedPromos":1,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":2,"campaignName":"Tarzan 2","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":4,"campaignName":"Tarzan 4","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":5,"campaignName":"Jabe 1","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":6,"campaignName":"dadsada","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":8,"campaignName":"Black Friday","startDate":"2022-02-01","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]}]
这是campaignsPromo的内容:
[ { IDCampaign: 1,
IDPromo: 1119,
promoType: 'CHRISTMASS',
associated: 1,
validated: 1,
promoName: 'Test Promo 1',
beginDate: '2020-11-26',
endingDate: '2020-11-29' },
{ IDCampaign: 1,
IDPromo: 107,
promoType: 'CHRISTMASS',
associated: 1,
validated: 0,
promoName: 'Test Promo 2',
beginDate: '2019-12-21',
endingDate: '2019-12-23' } ]
有任何想法吗? 从我的立场来看,我没有做错任何事,但这不是我第一次错过显而易见的事情。
PS:请忽略我的活动名为“Tarzan”的事实。
你没有分享有问题的代码,所以我会给出一个通用的答案。
当症状是一堆所有对象似乎都有一个属性是相同的项目数组时,它很可能正是由此引起的。 每个 object 可能共享同一个数组实例。
典型的错误如下所示:
var items = []; var containers = []; for (let i = 0; i < 3; ++i) { items.push(i); let container = {}; container.items = items; containers.push(container); } console.log(containers);
尽管人们可能期望甚至打算得到 3 个这样的对象:
[ { items: [ 0 ] }, { items: [ 0, 1 ] }, { items: [ 0, 1, 2 ] } ]
items
数组实际上是数组的同一个实例。 而你实际得到的更像是:
[ { items: [ 0, 1, 2 ] }, { items: [ 0, 1, 2 ] }, { items: [ 0, 1, 2 ] } ]
事实上,堆栈片段可视化工具实际上在可视化方面做得更好,因为它输出:
[ { "items": [ /**id:3**/ 0, 1, 2 ] }, { "items": /**ref:3**/ }, { "items": /**ref:3**/ } ]
通过这种方式,它试图通过给它一个ref:3
label 并用相同的ref:3
label 标记其他属性的值作为注释来告诉你它实际上是同一个数组。
我看到的原因通常源于对将数组分配给属性的含义的误解。 这样做不会创建数组的副本。 两个对象都引用同一个数组。
这可能很奇怪,因为:它在调试器中看起来是正确的,方法是在您逐步执行循环时检查数组的内容。 即使我们在循环中添加了诸如console.log(items)
甚至console.log(container)
之类的日志消息,我们可能仍然没有足够的线索表明出现了问题,因为那个数组实例的内容发生了变化对于循环的每次迭代,我们可以将它的版本转储为看起来正确的文本,但随后在下一次迭代中无意中更改了数组的内容。
但是如果我们在循环后记录整个containers
数组,您会发现每个 object 都有相同的数组实例。 如果只有一个 object 获取分配给它的数组,则分配一个数组还不错,但是如果将同一个数组分配给多个对象的属性,或者在循环中,您可能会遇到这个问题。
您可以尝试的一个打破习惯的方法是在主循环之后的第二个循环中检查所有对象,而不是将日志记录代码直接潜入第一个循环中。 它的效率较低,但如果您经常犯此类错误,它可以帮助您发现问题并实现正确性。
另一个打破习惯的是console.log(JSON.stringify(foo))
而不是console.log(foo)
因为浏览器中的 console.log 实际上会记住 object 的引用并向您显示它的当前内容,而不是它的内容它被记录的时间。 这取决于平台,其中 node.js 将记录为文本而不是引用。
祝你好运,小心!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.