【问题标题】:JavaScript Object Property not being replaced with new number [duplicate]JavaScript对象属性没有被新数字替换[重复]
【发布时间】:2020-10-01 00:15:03
【问题描述】:

所以我一直盯着这个问题一段时间了,我不明白出了什么问题。我正在尝试创建游戏 Yahtzee,并且我有一个函数可以随机生成 5 个骰子。当用户希望再次滚动时,也会重复使用此功能。我传入一个对象数组,每个对象都有一个数字属性,表示用户滚动的内容。我遇到了这个问题,我必须生成一个新的骰子集,而不是替换旧的。这是我的功能代码

function roll(theRoll){
    diceSet = theRoll;

    console.log("before")
    console.log(diceSet)

    for(let i = 0; i < diceSet.length; i++){
        if(diceSet[i].isHeld == false){
            diceSet[i].number = Math.floor((Math.random() * 6) + 1);
        }
        
        document.getElementById("die" + (i + 1) + "Img").src = "img/" + diceSet[i].number + ".png";
    } 
   
    console.log("After")
    console.log(diceSet)
    return theRoll;


}

现在我可能错了,但上面的代码应该可以正常工作,但我的“diceSet”在循环前后有相同的数字,但我不知道为什么属性没有改变。

这是我的输出

任何帮助将不胜感激,谢谢

【问题讨论】:

  • 也许在将其分配给 diceSet 之前尝试深度克隆 theRoll。您可以使用 github.com/davidmarkclements/rfdc 之类的库,也可以自己实现深度克隆。
  • 好像很奇怪,我自己试过,每次都得到不同的结果,你能提供一个jsfiddle的demo吗?
  • 它也因浏览器而异。唉,可以做得更一致
  • 所以当我遇到这个问题时,我使用的是 chrome,还有 ElectricShadow,我很想使用库来克隆,但是,由于项目的性能问题,我不能使用任何外部库

标签: javascript console.log


【解决方案1】:

值在变化;只是您将值记录到控制台,而控制台显示的是数组的当前值(在您查看它时),而不是记录时数组中的值。如果您想查看值的变化,请将数组转换为字符串,而不是记录数组。

function diceToString(theRoll)
{
  return theRoll.map(roll => roll.number).join(",");
}

function roll(theRoll){
    console.log("before")
    console.log(theRoll)
    console.log(diceToString(theRoll))

    for(let i = 0; i < theRoll.length; i++){
        if(theRoll[i].isHeld == false){
            theRoll[i].number = Math.floor((Math.random() * 6) + 1);
        }
        
        document.getElementById(`die${i + 1}Img`).src = `img/${theRoll[i].number}.png`;
    } 
   
    console.log("After")
    console.log(theRoll)
    console.log(diceToString(theRoll))
    return theRoll;
}

dice = [
  {"isHeld": false, "number": 0},
  {"isHeld": false, "number": 0},
  {"isHeld": false, "number": 0},
  {"isHeld": false, "number": 0},
  {"isHeld": false, "number": 0}
]

roll(dice);
roll(dice);
roll(dice);
roll(dice);
<img id="die1Img" src="" alt="" />
<img id="die2Img" src="" alt="" />
<img id="die3Img" src="" alt="" />
<img id="die4Img" src="" alt="" />
<img id="die5Img" src="" alt="" />

您还可以运行 sn-p 并查看输出(以及值的变化),然后将其与浏览器控制台中的日志进行比较以查看差异。

【讨论】:

  • 好的,很高兴听到,我担心它根本不会改变任何东西。我将它们更改为字符串以查看,感谢您的帮助!
【解决方案2】:

这是因为 JS 中的数组和对象是可变的,也就是说它们是通过引用复制。换句话说,如果您将一个对象(或数组)传递给任何函数(没关系,它是您的或默认的),您实际上是传递了引用,而不是副本。

function addOne(obj) {
  obj.value += 1;
}

function addTwo(obj) {
  obj.value += 2;
}

const testObj = {
  value: 0
}

addOne(testObj);
addTwo(testObj);

console.log(testObj)

testObj 从未被重新分配,但 value 最终等于 3。当函数addTwo 被调用时,它采用了已经更新的值(等于1)。实际上,当您将可变实体传递给 console.log 方法时,也会发生同样的事情 - 它需要一个引用,您会看到对象的“实际”状态,而不是调用时的快照。

这种行为还有另一个原因 - 时间间隔。此答案简要介绍了它们(请参阅“更多详细信息”块):https://stackoverflow.com/a/30363526/6053654

避免这种行为的最简单方法是将数据转换为不可变类型。字符串非常适合这种情况,您可以在将对象登录到控制台之前简单地JSON.stringify

【讨论】:

  • 好的,感谢您提供的信息,如果以后出现此问题,我会记住这一点!
猜你喜欢
  • 1970-01-01
  • 2021-11-26
  • 2020-03-23
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多