【问题标题】:Javascript pushing objects into array changes entire arrayJavascript将对象推入数组会改变整个数组
【发布时间】:2012-06-26 23:07:14
【问题描述】:

我正在使用特定的游戏制作框架,但我认为这个问题适用于 javascript

我试图制作一个旁白脚本,以便玩家可以看到“兽人打你”。在他的屏幕底部。我想一次显示最后 4 条消息,如果他们愿意,可能允许玩家回头查看日志中的 30-50 条消息。为此,我设置了对象和一个数组以将对象推入。

所以我一开始就设置了一些这样的变量...

servermessage: {"color1":"yellow", "color2":"white", "message1":"", "message2":""},
servermessagelist: new Array(),

当我通过操纵 servermessage.color1 ... .message1 等多次使用此命令(如下)和事件调用的不同数据时...

servermessagelist.push(servermessage)

它用该数据的副本覆盖整个数组...知道为什么或我能做些什么。

所以如果我推动 color1 "RED" 和 message1 "Rover".. 数据是正确的,那么如果我推动 color1"yellow" 和 message1 "Bus" 数据是 .color1:"yellow" .message1:"Bus" 的两个副本

【问题讨论】:

标签: javascript arrays object


【解决方案1】:

当您将servermessage 推送到servermessagelist 时,您实际上(或多或少)推送了对该对象的引用。因此,对servermessage 所做的任何更改都会在您引用它的任何地方反映出来。听起来您想要做的是将对象的克隆推送到列表中。

如下声明一个函数:

function cloneMessage(servermessage) {
    var clone ={};
    for( var key in servermessage ){
        if(servermessage.hasOwnProperty(key)) //ensure not adding inherited props
            clone[key]=servermessage[key];
    }
    return clone;
}

然后每次你想将消息推送到列表中时:

servermessagelist.push( cloneMessage(servermessage) );

【讨论】:

  • 有没有更简单的方法可以通过声明一个对象数组来做到这一点???我不知道该怎么做。
  • 每次推送servermessage 时都必须进行此克隆。一旦你改变它,克隆它,然后推送它的克隆。
  • 你可以每次使用第一个对象的属性声明一个新对象并将值设置为null或''
  • @user1481372 编辑后的版本可能更容易实现。 cloneMessage 你可以逐字使用。将您的推送声明替换为我在您所做的任何地方都有的声明。这只是为您创建消息的克隆。
【解决方案2】:

当您将对象添加到数组中时,它只是对添加的对象的引用。通过将对象添加到数组中不会复制对象。因此,当您稍后更改对象并将其再次添加到数组中时,您只需要一个包含多个对同一对象的引用的数组。

为数组的每个添加创建一个新对象:

servermessage = {"color1":"yellow", "color2":"white", "message1":"", "message2":""};
servermessagelist.push(servermessage);
servermessage = {"color1":"green", "color2":"red", "message1":"", "message2":"nice work"};
servermessagelist.push(servermessage);

【讨论】:

    【解决方案3】:

    在将对象推入数组之前,有两种方法可以使用深拷贝。 1. 通过对象方法创建新对象,然后推送。

    servermessagelist = []; 
    servermessagelist.push(Object.assign({}, servermessage));
    
    1. 通过 JSON stringigy 方法创建对象的新引用,并使用 parse 方法推送。

      servermessagelist = []; servermessagelist.push(JSON.parse(JSON.stringify(servermessage));

    此方法对嵌套对象很有用。

    【讨论】:

      【解决方案4】:

      servermessagelist: new Array() 每次执行时都会清空数组。仅在最初初始化数组时执行该代码一次。

      【讨论】:

      • 消息列表在我的初始函数中,推送在在 websocket 事件上运行的更新函数中......
      • 啊,我的错,我没有从你的代码示例中得到那个。但正如 nbrooks 所说,在 javascript 中,对象总是作为引用传递,这就是它无法正常工作的原因。
      【解决方案5】:

      我也有同样的问题。我有一些复杂的对象要推入数组。我做了什么;我使用 JSON.stringify() 将 JSON 对象转换为字符串并推入数组。

      当它从数组返回时,我只是使用 JSON.parse() 将该字符串转换为 JSON 对象。

      这对我来说很好,虽然它是一个更全面的解决方案。 如果你们有其他选择,请在此处发布

      【讨论】:

        【解决方案6】:

        我不知道为什么还没有建议使用 JSON 方法来执行此操作。 您可以先对对象进行字符串化,然后再次对其进行解析以获取对象的副本。

        let uniqueArr = [];
        let referencesArr = [];
        let obj = {a: 1, b:2};
        
        uniqueArr.push(JSON.parse(JSON.stringify(obj)));
        referencesArr.push(obj);
        
        obj.a = 3;
        obj.c = 5;
        uniqueArr.push(JSON.parse(JSON.stringify(obj)));
        referencesArr.push(obj);
        
        //You can see the differences in the console logs
        console.log(uniqueArr);
        console.log(referencesArr);

        【讨论】:

          【解决方案7】:

          此解决方案也适用于包含嵌套键的对象。

          在推送之前,将obj字符串化

          JSON.stringify(obj)
          

          而当你使用的时候,通过解析

          JSON.parse(obj);
          

          【讨论】:

          • 这是唯一对我有用的东西。我需要将数组推送到多维循环中的另一个数组中。我想利用增量推送状态,但发现所有数组都在数组内。类似于循环结束时的样子。我知道词法范围和闭包,假设它与外部范围问题有关。我尝试以多种方式在循环中克隆数组,但发现使用 JSON.stringify 是唯一有效的方法。我假设 JSON.stringify 基本上克隆了数组,但不确定为什么 .splice 和 .concat 对我不起作用。
          【解决方案8】:

          正如上面多次提到的,最简单的方法是将它变成一个字符串并将其转换回 JSON 对象。

          this.<JSONObjectArray>.push(JSON.parse(JSON.stringify(<JSONObject>)));
          

          像魅力一样工作。

          【讨论】:

            猜你喜欢
            • 2015-10-19
            • 2011-02-13
            • 1970-01-01
            • 2018-11-08
            • 1970-01-01
            • 2021-05-06
            • 1970-01-01
            • 1970-01-01
            • 2017-06-24
            相关资源
            最近更新 更多