JavaScript中for循环返回值莫名翻倍问题排查
代码背景
为避免小数运算问题,所有金额均乘以100处理,相关初始化代码如下:
let dif100 = { rem : function(n){return n%10000}, num: 10000, name : "ONE HUNDRED"} // 0 let dif20 = { rem : function(n){return n%2000}, num: 2000, name : "TWENTY"} // 1 let dif10 = { rem : function(n){return n%1000}, num: 1000, name : "TEN"} // 2 let dif5 = { rem : function(n){return n%500}, num: 500, name: "FIVE"} // 3 let dif1 = { rem : function(n){return n%100}, num: 100, name: "ONE"} // 4 let difqu = { rem : function(n){return n%25}, num: 25, name: "QUARTER"} // 5 let difdime ={ rem : function(n){return n%10}, num: 10, name: "DIME"}//6 let difnic = { rem : function(n){return n%5}, num: 5, name: "NICKEL"} //7 let difpen = { rem : function(n){return n%1}, num: 1, name: "PENNY"} //8 let difArr = [dif100,dif20,dif10,dif5,dif1,difqu,difdime,difnic,difpen] cid = [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]] let cashBox = cid.reverse() for(let i = 0; i < cashBox.length; i++){ cashBox[i][1] = Math.round(cashBox[i][1] *100) }
测试情况
手动赋值dif(现金与价格差值乘以100)测试:
- 当
dif=18000(对应180美元)时,运行以下代码返回正确找零数组:
dif = 18000 answerArr = [] for(let i = 0; i < difArr.length; i++){ if(dif < difArr[i].num){ dif = dif } else if(difArr[i].rem(dif) == 0){ if(cashBox[i][1] >= dif){ answerArr.push([difArr[i].name, dif/100]) dif = 0 } else if (cashBox[i][1] < dif){ answerArr.push([difArr[i].name, cashBox[i][1]/100]) dif = dif - cashBox[i][1] } }else { if(cashBox[i][1] >= dif - difArr[i].rem(dif)){ answerArr.push([difArr[i].name, (dif - difArr[i].rem(dif))/100]) dif = difArr[i].rem(dif) } else if (cashBox[i][1] < dif - difArr[i].rem(dif)){ answerArr.push([difArr[i].name, cashBox[i][1]/100]) dif = dif - cashBox[i][1] + difArr[i].rem(dif) } } } answerArr //返回 [["ONE HUNDRED",100],["TWENTY",60],["TEN",20]]
- 当
dif=18100(对应181美元)时,返回数组为[["ONE HUNDRED",100],["TWENTY",60],["TEN",20],["ONE",2]],最后1美元金额莫名翻倍;dif=18050时也存在类似异常。
排查方向
核对
cashBox与difArr的索引对应关系:cashBox由cid.reverse()生成,需逐一确认每个索引位置的币种是否与difArr完全匹配。比如反转后的cashBox第一项是["ONE HUNDRED",10000],对应difArr[0]是正确的,但后续的ONE美元、QUARTER等币种的索引是否一一对应?索引不匹配会导致取错现金盒中的金额,引发计算错误。跟踪循环每一步的关键变量值:
在循环内部添加console.log,打印每一轮的i、difArr[i].name、当前dif值、cashBox[i][1]、dif - difArr[i].rem(dif)的计算结果。重点观察处理ONE美元(i=4)时的变量变化,看是否出现预期外的数值修改。检查else分支的
dif更新公式:
在else分支的第二个条件(cashBox[i][1] < dif - difArr[i].rem(dif))中,dif = dif - cashBox[i][1] + difArr[i].rem(dif)这个公式是否符合逻辑?代入异常场景的数值(比如dif=100时),计算该公式的结果是否合理,是否会导致dif被错误增加。确认数组反转的副作用:
cid.reverse()会直接修改原数组cid,后续如果重复测试可能导致cashBox的内容意外变化。可以改成let cashBox = [...cid].reverse()创建数组副本,避免修改原数组带来的干扰。
内容的提问来源于stack exchange,提问作者Code Noober

