Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/452.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么添加到状态中的对象数组会改变该数组中的其他对象?(反应)_Javascript_Arrays_Reactjs - Fatal编程技术网

Javascript 为什么添加到状态中的对象数组会改变该数组中的其他对象?(反应)

Javascript 为什么添加到状态中的对象数组会改变该数组中的其他对象?(反应),javascript,arrays,reactjs,Javascript,Arrays,Reactjs,一般来说,我对反应/发展比较陌生(大约5个月),我偶然发现了以下问题,这让我非常疯狂。我想知道我是否愚蠢,是否遗漏了一个基本概念,或者这是更深层次的东西 要向您介绍我的项目背景以及这个问题是如何出现的: 我正在构建一个计算器应用程序,非常像你在谷歌上搜索“计算器”时得到的那个。我正在尝试编写一个函数,每当用户单击计算器上的按钮时,它都会将与显示相关的所有内容保存为一个对象,并将该对象添加到一个数组中,该数组保持在计算器整个“输入历史”的状态。这样,当用户希望逐个删除显示值时,计算器可以返回输入历

一般来说,我对反应/发展比较陌生(大约5个月),我偶然发现了以下问题,这让我非常疯狂。我想知道我是否愚蠢,是否遗漏了一个基本概念,或者这是更深层次的东西

要向您介绍我的项目背景以及这个问题是如何出现的:

我正在构建一个计算器应用程序,非常像你在谷歌上搜索“计算器”时得到的那个。我正在尝试编写一个函数,每当用户单击计算器上的按钮时,它都会将与显示相关的所有内容保存为一个对象,并将该对象添加到一个数组中,该数组保持在计算器整个“输入历史”的状态。这样,当用户希望逐个删除显示值时,计算器可以返回输入历史数组中的一个索引,并及时返回到以前的设置。这样,计算器在删除(指数、不匹配的括号等)时仍然可以显示漂亮的动态渲染样式,而不必编写非常长、复杂且几乎肯定有缺陷的删除函数

为了实现这一点,我告诉我的程序,在每次状态改变后(保留显示值),将当前设置和显示添加到输入历史数组中。我选择将此函数放在componentDidUpdate方法中,并通过仅在this.state.inputIstUpdated为false时调用它来确保它只触发一次,每次向显示中添加内容时都会发生这种情况

这是我的函数,在componentDidUpdate()方法中:

输入对象中的每个值都可能受到用户输入内容的影响,并以某种形式出现在显示中

问题是这个

用户在计算器中输入5。NewInAuthist记录单个对象,其currentMath值为5。(这是意料之中的)。React DevTools还将this.state.inAuthist显示为一个对象的数组,其currentMath值也是5(如预期的)问题就在这里:假设用户在计算器中输入“+”。NewInAuthist记录一个currentMath值为“5+”的单个对象,这是正确的,并且已将一个新对象添加到此.state.InAuthist,其currentMath值也是“5+”,但该数组中另一个元素(我们之前添加的元素)的currenMath值也已更改,从“5”更改为“5+”。每次我更新显示器时都会发生这种情况;this.state.inputHist数组中每个对象的currentMath属性将更新为当前currentMath属性,而不是保存它原来拥有的属性

这对我来说毫无意义。我尝试过将对象连接到数组的其他方法,在谷歌上下搜索,寻找解决方案,但很难找到任何有用的方法

请让我知道你认为这里可能发生了什么,如果你需要更多的信息/代码。我想给你足够的背景资料等等,这样你就可以回答我的问题,而不必添加任何无关的内容,但如果我不想随便说的话

下面是更多的代码:

此功能将数字/操作/所有内容添加到显示中

addToDisplay(input) {
    this.setState((prevState) => {
        let calcArr = prevState.newCalc ? [] : prevState.currentMath
        if (prevState.lastInput=== '□') {
            calcArr.pop(); 
        }

        if (prevState.lastInput === ' - ' && /[×\-÷\+]/.test(prevState.currentMath[prevState.currentMath.length-2])) {
            calcArr[calcArr.length-1] = ' -'

        }

        calcArr.push(input)
        return { 
            currentMath : calcArr,
            calcActive : true,
            lastInput : input,
            newCalc : false, 
            inputHistUpdated : false
        }
    });
}
这两个函数处理显示中动态呈现的UI——当用户输入左括号时添加特殊样式的右括号,当用户在指数中上升一级时添加必要的不可见的
,这具有不同的样式

  rightParensFunc() {

    let styledParens = `<span class='parens exp-${this.state.exponentCount}'>)</span>`; 

    this.setState((prevState) => {
        return {
            rightParensArr : [styledParens, ...prevState.rightParensArr], 
            inputHistUpdated : false 
        }
    });


}

spanFunc() {
    let counter = this.state.exponentCount; 
    let spans = ''; 
    while (counter > 0) {
        spans = spans + '</span>';
        counter--;
    }; 
    this.setState({
        spanStr : spans,
        inputHistUpdated : false
    })   
}

您的问题似乎在这里:

让NewInAuthist={
currentMath:this.state.currentMath,//此处
exponentCount:this.state.exponentCount,
spanStr:this.state.spanStr,
rightParensArr:this.state.rightParensArr,//此处
}
JavaScript数组和对象作为引用存储在变量中。您可以阅读更详细的含义解释(在“解释”标题下)

要解决此问题,您需要创建阵列的真实副本,如下所示:

let newInputHist = {
  currentMath : [ ...this.state.currentMath], 
  // keep others as usual
}
let newInputHist = {
  currentMath : JSON.parse(JSON.stringify(this.state.currentMath)), 
  // keep others as usual
}
让NewInAuthist={
currentMath:[…this.state.currentMath],
exponentCount:this.state.exponentCount,
spanStr:this.state.spanStr,
rightParensArr:[…this.state.rightParensArr],
}
怎么搞的? 历史记录中的数组和用于存储当前数学的数组在内存中引用了相同的数组。意思是一个改变一个改变两个

这是怎么解决的 通过使用spead语法
[…array]
,我们创建了一个全新的数组。没有更多的意外变化

另外:在
addToDisplay
函数中,由于与上面相同的原因,您正在意外地改变状态。更改为:

让calcArr=prevState.newCalc?[]:[…prevState.currentMath]

currentMath
是一个数组(对象),因此由同一引用传递

这就是应用程序中发生的情况:

Memory Location   |   Variable pointing at it

     xyz                   currentMath
添加5时:

let newInputHist = {
  currentMath: this.state.currentMath, 
  // others
}

// value of currentMath is 5
inputHistory = [
  { currentMath: <value points to xyz memory>, // others }
]
方法2
或者像这样做一份深度拷贝:

let newInputHist = {
  currentMath : [ ...this.state.currentMath], 
  // keep others as usual
}
let newInputHist = {
  currentMath : JSON.parse(JSON.stringify(this.state.currentMath)), 
  // keep others as usual
}
这些应该可以解决你的问题。我鼓励你仔细阅读

我还想在这里提到您希望使用方法2的场景。 假设currentMath中还有另一个对象:

currentMath = [ { key: value }, <some primtive like string> ]
currentMath=[{key:value},]

在这种情况下,
currentMath[0]
[…currentMath[0]]
将指向同一内存位置,尽管
currentMath[1]
[…currentMath[1]
将指向不同的内存位置。您可以使用深度复制方法来解决此问题。

您可以显示更多代码吗?看起来状态中的所有对象都引用了内存中的同一个对象,但我没有立即在给出的代码中看到罪魁祸首。
console.log(newinpurtist)
的输出可能就足够了。对不起,这里是total newb——我如何显示该输出?你想看看m里面有什么吗
currentMath = [ { key: value }, <some primtive like string> ]