JavaScript如何从两个数组中删除对象引用?

3

当两个数组中存在相同的对象引用时,这些对象是等价的,更新其中一个会影响另一个。

然而,在一个数组中删除对象并不会在另一个数组中删除它。

为什么呢?

var a1 = [
  {i: 0, s: 'zero'}, 
  {i: 1, s: 'one'}
];

var a2 = [
  a1[0],
  a1[1]
];

// items point to same reference
print(a1[0] === a2[0]); // true (equivalent)

// updating one affects both
a1[0].s += ' updated';
print(a1[0] === a2[0]); // true (still equivalent)
print(a1[0]); // {"i":0,"s":"zero updated"}
print(a2[0]); // {"i":0,"s":"zero updated"}

// however, deleting one does not affect the other
delete a1[0];
print(a1[0]); // undefined
print(a2[0]); // {"i": 0, "s": "zero"}

有趣的是,从其中一个属性中删除内容会影响另一个属性。
delete a1[1].s;
print(a1[1]); // {"i":1}
print(a2[1]); // {"i":1}

https://jsfiddle.net/kevincollins/4j6hj2v7/3/


13
你删除的是对值的引用,而不是值本身。可以把它看作给一个人起名字,如果停止叫他们Chris,他们并不会突然消失。 - Halcyon
2
对象使用引用进行分配。因此,当您执行a1[0]时,它将获取其引用并将其复制到数组中,并将使用它来访问值。因此,当您删除引用时,您会删除原始位置,因此它将反映在所有变量中。 - Rajesh
不要在数组上使用 delete。只需将索引设置为 nullundefined - Bergi
@Bergi 既然数组是对象,使用 delete 会有什么危害呢?我知道你正在创建一个带洞的数组,但这对标准 API 来说并不是问题。 - bren
@MayorMonty 是的,没错,但是你只是替换了数组中存储的值,而没有改变引用本身。 - Rajesh
@MayorMonty 空洞数组确实存在问题,会影响理解、性能和正确性。 - Bergi
2个回答

1
为了回答为什么最后一个print(a2[0]);仍然显示值,让我们开始分析代码。
您的a1是一个数组,当您使用对象初始化它时,它将创建对象并存储其引用。
var a1 = [
  {i: 0, s: 'zero'}, // ref 1001
  {i: 1, s: 'one'}   // ref 1002
];

通过您的评论,这部分内容很清楚,但是当您执行delete a1 [0]时会发生什么?

它会删除属性而不是对象吗?答案是否定的。它将删除存储在a1 0 索引处的属性,并将其设置为undefined 。 但是,如果您删除该引用所持有的对象的属性,则会在两个地方显示:sample

那么对象会发生什么变化? 值被保留并且如果没有任何人引用它,将被垃圾回收。在您的情况下,由于a2 [0] 仍在访问它,因此它将保留该值。

您可以参考以下sample


0

就像@Halcyon所说的那样,你删除的是引用,而不是对象本身。为了说明这一点,看下面的例子:

var a = 2
var b = [a, 2, 3, 4]

如果你删除了 b[0],你只会删除引用,因此 a===2。但是,如果你通过 delete a 删除了 a 的引用,则 b 中的值将被更改为 undefined,因为该位置上原来存在的引用不再存在。

1
这差不多是我预期的。然而在这个例子中,a 没有被删除。https://jsfiddle.net/kevincollins/f30euchx/ - Kevin Collins
1
@KevinCollins 记住,字面量(数字、字符串等)不能被删除,如果你引用了一个字面量,就不能使用 delete 删除它。 - bren

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接