为什么 array.push() 看起来会无限次地推入元素?

3

请考虑以下 JavaScript 代码:

>> a = [1, 2]
  Array [ 1, 2 ]

>> a.push(a) 
  Array [ 1, 2, Array[3] ] 

在扩展数组a时,我们得到一个具有无限深度的数组。(在firefox开发者控制台上查看)
Array[3]
| 0: 1
| 1: 2
  2: Array[3]
  | 0: 1
  | 1: 2
  | 2: Array[3]
    | 0: 1
    | 1: 2
    | 2: Array[3]
    ....

[1] 为什么会出现多次添加的情况?
[2] 它停止的深度是多少?


3
循环引用可能可以解释这个。 - Manish
2
要理解递归,你必须先理解递归。 - Drew Kennedy
5个回答

4

只需推送一次。当数组引用自身(循环引用)时,您会看到插入的多个数组。显示效果取决于浏览器。

如果您尝试获取JSON字符串,那么JSON.stringify会出现错误。

Circular reference in value argument not supported

var a = [1, 2]
console.log(a);

a.push(a);
console.log(a);
JSON.stringify(a);
.as-console-wrapper { max-height: 100% !important; top: 0; }


1
SO很好地解决了引用问题,并将它们用**包围起来。+1 :) - 31piy
1
但实际上,它只存储[1, 2, 对内部数组的引用]。其中包含对外部数组和内部数组中第三个元素的引用,类似于 [1, 2, [1, 2, [1, 2, [1, 2, ...]]]] - Nina Scholz
这个是否类似于Python存储范围的方式?它不会存储整个数组,而是在需要时计算它。 - TheChetan
@TheChetan,抱歉,我不懂Python。 - Nina Scholz

1
它不会被无限次推送。问题在于Firefox开发者控制台如何呈现该元素。展开数组并再次单击其下方的内容,将始终显示数组的外观。因此,您可以无限次地展开和单击它,但仍然只有一次。

1
你创建了一个循环引用。
当你将数组推入其本身时,数组中的最后一个元素成为整个数组的引用,包括该最后一个元素。因此,最后一个元素中的最后一个元素也是对整个数组的引用,以此类推。
它在同样的意义上是无限的,就像一个圆是无限的一样,“多次添加”只是在同样的意义上,如果你在一个圆上走了多于一圈,你会多次经过同一点。

0
因为 JavaScript 给出的是对变量 'a' 的引用,而不是实际对象本身,所以如果你将 a 推入自身,就会推入保存对象的内存地址,从而创建一个循环引用。

[1, 2, 指向该对象的引用]


什么?请再详细解释一下。 - PeterMader
当你创建变量a = [1, 2]的对象时,'a'保存了内存地址,其中包含对象[1, 2]的信息,当你说var b = a;时,你传递了引用,即包含[1, 2]数组对象的内存地址。所以,如果你说b.push(3),它将添加到该对象中的另一个项,即[1, 2, 3],但地址不会改变,因此现在a和b相等[1, 2, 3],如果你调用a.push(a),这意味着你有一个对象,它是[1, 2,* 内存地址本身 *],所以你可以深入进去,因为它是同一个对象。 - racz_gabor
我知道。那被称为循环引用。你为什么不把它加入你的回答呢?现在听起来有点令人困惑。 - PeterMader

0

实际上只推送了一次。它并没有推送数组元素,而是数组的地址。Firefox控制台只是试图显示其中的内容,但最终会无限地显示相同的内容。

不仅仅是Firefox,Chrome也会这样做。


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