Javascript-为什么对象数组不相等?

Javascript-为什么对象数组不相等?,javascript,arrays,object,Javascript,Arrays,Object,我有一些javascript代码,我正试图清理。。。我最初以“暴力”风格编写了对象数组(称为myData)的定义。蛮力样式定义了一个由4个对象组成的数组(数组大小始终为4)。这样定义时,我的应用程序运行良好。程序后面的代码将读取JSON并以类似以下语法更新各种元素: myData[2].Quarter = "Q2"; 当我尝试清理/合并myData的定义时,我的代码运行时没有语法错误,但数组的所有4个元素都以相同的值结束,而在蛮力样式中,数组中的每个对象都以不同的值结束。唯一不同的是这两个定义

我有一些javascript代码,我正试图清理。。。我最初以“暴力”风格编写了对象数组(称为myData)的定义。蛮力样式定义了一个由4个对象组成的数组(数组大小始终为4)。这样定义时,我的应用程序运行良好。程序后面的代码将读取JSON并以类似以下语法更新各种元素:

myData[2].Quarter = "Q2";
当我尝试清理/合并myData的定义时,我的代码运行时没有语法错误,但数组的所有4个元素都以相同的值结束,而在蛮力样式中,数组中的每个对象都以不同的值结束。唯一不同的是这两个定义。 这就是我所说的“蛮力”,我的整个代码集工作得很好…它实际上是同一个对象复制了4次

var myData = [
     {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    },
        {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    },
        {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    },
        {
        Quarter: 'EMPTY',
        Field_Cloud:0,
        Field_Cloud_Renew:0,
        Field_On_Premise:0,
        Field_Total:0,
        OD_Cloud:0,
        OD_Cloud_Renew:0,
        OD_On_Premise:0,
        OD_Total:0,
        Field_OD_Total:0
    }   
    ];
我试图将其整合为我认为应该是相同的代码,但我的应用程序不再工作。症状是数组的所有4个对象最终都具有相同的值

合并(但不完整)代码:


我做错了什么,如何定义myData是一种正确的整合方式?

您可能需要使用面向对象编程和继承:

var myDataStruct = {
    Quarter: 'EMPTY',
    Field_Cloud:0,
    Field_Cloud_Renew:0,
    Field_On_Premise:0,
    Field_Total:0,
    OD_Cloud:0,
    OD_Cloud_Renew:0,
    OD_On_Premise:0,
    OD_Total:0,
    Field_OD_Total:0
};

var myData = Array.from({length:4}, ()=>Object.create(myDataStruct));
或者像这样克隆该对象四次(不利于内存消耗,没有真正的优势):


它们在记忆中的样子:

1) 您的方法,将相同的obj推入阵列:

//the object
123:
  {Quarter:"Empty",...}
//the array
124: 123
125: 123
126: 123
127: 123
128: null
2) 继承方法:

//the prototype
123:
  {Quarter:"empty",...}
//the subobjects
124:
  { prototype: 123}
125:
  { prototype: 123}
126:
  { prototype: 123}
127:
  { prototype: 123}
//the array
128:124
129:125
130:126
131:127
132: null
所以用你的方法,改变一个数组元素,实际上改变了存储在123的对象,所以它们相互干扰。使用继承方法,例如更改第一个对象将更改124处的对象,在propertylookup上,它将首先在124处搜索属性,如果未找到,则在123处搜索。所以如果你这样做了

myData[0].Quarter = "Full";
内存将更改为:

//the prototype
123:
  {Quarter:"empty",...}
//the subobjects
124:
  {Quarter: "Full", prototype: 123}
其结果是:

myData[0].Quarter // "Full", looked up in 124
myData[1].Quarter // "empty", as not found in 125 and therefore looked up in 123

问题在于Javascript通过引用处理对象

如果创建一个对象并将其推送到某个数组四次,则数组中有四个对同一对象的引用。如果随后更改对象,此更改似乎会影响阵列中的所有对象。但这只是因为数组包含对一个对象的四个引用,而不是一个原始对象的四个副本。如果您需要添加对象的副本,您需要首先创建这些副本,而Javascript中的副本没有其他语言中的副本那么简单

只需将存储对象的变量(包括Javascript中的函数和数组,每一个都是某种更具体的对象)视为包含存储对象的内存地址。如果使用该变量访问对象,它只是指向一些内存。如果将变量的值赋给其他变量,或将其作为参数传递给某个函数(如数组的push()),则复制并传递的是地址,而不是对象的属性

当涉及到复制/克隆对象时,有更多方面需要遵守:如果您的对象具有object(或array或function)类型的属性,您可能还需要复制这些属性。它们也可能具有这样的特性。那么,您需要对象的浅拷贝还是深拷贝?对象可能具有您可以访问的属性,但某些操作不会处理这些属性,但您仍然希望复制它们。这方面影响可枚举和不可枚举属性。最后,每个对象可能都有自己的属性和“派生”属性,有些操作处理所有这些属性,或者只处理对象自己的属性

因此,请注意克隆对象实际需要的方法

您可能会问:为什么Javascript不隐式创建副本?我认为这是由于语言的结构简单。一旦解决了这个“问题”,您可能就会意识到Javascript的速度有多快。我宁愿自己处理这个问题,也不愿忍受一种语言浪费时间来复制对象或实现写时复制的魔力

例子 深度复制、性能低下、所有可枚举属性 浅拷贝,性能好,拥有可枚举属性

您正在将相同的对象引用推送到数组中,这意味着当您修改数组中的一个对象时,所有对象都会被修改

要解决这个问题,可以使用
Object.assign()
或对象扩展语法,比如
myData.push(Object.assign({},myDataStruct))
,它将创建一个空对象,将其与
myDataStruct
对象合并,然后将其推入数组

有用链接:


因为对象在JS中是通过引用传递的-所以数组在每个索引中都包含相同的对象-更新1将更新每个对象。您需要将对象克隆到每个索引中-搜索该索引。您为数组的4个索引添加了相同的引用。。。当您更改其中一个副本时,您可能会问:为什么Javascript不隐式创建副本,原因如果我做
let current=users[0];current.name=“Jack”
,我希望用户[0]也能改变……当然,你是对的。。。从特殊意图的角度来看。不过,我猜还有其他意图可以从隐式复制中获益。最终,我喜欢Javascript,因为它的简单性,当涉及到实现运行时或者假设运行时最有可能处理这个问题时。(当然,这也适用于其他语言。)工作非常出色。谢谢
//the prototype
123:
  {Quarter:"empty",...}
//the subobjects
124:
  {Quarter: "Full", prototype: 123}
myData[0].Quarter // "Full", looked up in 124
myData[1].Quarter // "empty", as not found in 125 and therefore looked up in 123
copy = JSON.parse( JSON.stringify( original ) );
copy = Object.assign( {}, original );