操纵数组中的对象会更改数组外的对象吗?

时间:2017-12-04 19:00:56

标签: javascript arrays node.js

我不明白为什么会发生这种情况。让我们说我定义一个对象并创建一个3对象的数组。如果我修改数组中的对象,它会影响对象的所有实例吗?有人可以解释为什么会这样吗?另外,如何使用对象的独立“Copies”创建一个数组以获得所需的行为?谢谢!

例如

library(data.table)

#Set random seed
set.seed(2017)

#Create a table with the attributes we need
x = data.table(rbind(data.frame(Field1 = 1:12,Field2 = rep(1:3, each = 4), Value = runif(12)),
               data.frame(Field1 = 1:12,Field2 = rep(1:3, each = 4), Value = runif(12))))

#Let's order by Field2/ Field1 / Value
x = x[order(Field2,Field1,Value)]

#Check
print(x)

# This works, but requires 2 steps which can complicate things when needing 
# to pull other attributes too.
(x[,.(Value = sum(Value)),.(Field2,Field1)][,.SD[which.max(Value)],.(Field2)])

#This instead provides the row corresponding to the largest Value.
(x[,.(Field1 = Field1[which.max(Value)]),.(Field2)])

# This is what I was ideally looking for but it only returns the first row of the attribute 
# regardless of the value of Value, or the corresponding sum.
(x[,.(Field1 = Field1[which.max(sum(Value))]),.(Field2)])

# This works but seems clumsy

(x[, 
.SD[, .(RKCNT=length(.I),TotalValue=sum(Value)), .(Field1)]
[,.(RKCNT = sum(RKCNT), TotalValue = sum(TotalValue), 
Field1 = Field1[which.max(TotalValue)])], 
.(Field2)])

3 个答案:

答案 0 :(得分:2)

与基元(字符串,数字,布尔值,符号null,未定义)相反,javascript中的对象由reference传递。变量用作这些对象的占位符/指针。要创建没有变异风险的对象副本,您可以使用spread(禁止兼容性):

const newObject = { ...testObject };

或传统上, Object.assign() ,传递空对象文字以避免原始testObject的可变性:

const newObject = Object.assign({}, testObject);

深度克隆而言,MDN建议使用JSON.parse()JSON.stringify()的组合。例如:

const testObject = { value: "a", other: { value2: b } }; 

const newObject = JSON.parse(JSON.stringify(testObject));

答案 1 :(得分:0)

您正在循环中反复推送相同对象的引用。

for(i=0; i < 3; i++){
   var newobj = testObject; //no new object,same object's reference again 
   objArray.push(newobj); //push new object to array
   }

应该是

for(i=0; i < 3; i++){
   var newobj =  {"value1":"a","value2":"b"}; //make a new testObject
   objArray.push(newobj); //push new object to array
   }

答案 2 :(得分:0)

在JavaScript中创建对象时,实际上是在为该对象创建引用。您可以将其存储在变量中并传递它...也许将其附加到数组中。当您对对象引用进行操作时,它会找到引用指向并更新它的原始对象。因此,当您使用.push时,它不会创建新对象,而只是将引用推送到该对象。如果您在一个位置更新它,它将在另一个以及您已分配该引用的任何其他位置更新它。

将对象复制到新对象通常称为 cloning 。在JavaScript中克隆对象有很多不同的方法,结果各不相同。

您可以使用var newobj = { ...testObject }作为另一个答案建议。此扩展运算符基本上复制testObject的属性并创建一个新对象(使用外部{ }声明)。然后将对 new 对象的引用分配给newobj。您可以将其视为:

var newobj = {
  value1: testObject.value1,
  value2: testObject.value2,
};

然而,你应该记住,这只给你一个级别的克隆。也就是说,如果您的对象包含其他对象,则该对象的引用将被指定为属性而不是该对象的克隆。例如:假设你有:

var testObject = { obj: { a: "b" } };
var newobj = { ...testObject };
delete testObject.obj.a;
console.log(newobj); // { obj: {} }

为了解决这个问题,您需要执行所谓的深度克隆,在JavaScript中可以通过递归克隆同时也是对象的对象属性来完成。有很多方法可以做到这一点,包括lodash等库或本土函数。关于SO的一个例子:What is the most efficient way to deep clone an object in JavaScript?

最后,如果testObject应该是对象模板或其他newobj派生的初始状态,那么使用函数可能更有意义:

function newObjFactory() {
  return {
    value1: "a",
    value2: "b",
  };
}

然后你可以做var newobj = newObjFactory()每次你得到一个新对象,因为每次调用和return编辑时,函数都会创建一个新对象。