更改初始对象的值后Javascript对象引用中断

时间:2013-04-28 01:48:00

标签: javascript javascript-objects shuffle slice

我试图理解我对JavaScript对象的困惑。具体来说,我有兴趣找到什么,如果有的话,导致对象引用中断。

为了演示这种现象,我在Chrome的JavaScript控制台中添加了一些输出。请注意,我在这里使用数组,但考虑到JS中数组和对象之间的细微区别,我们希望对象的行为类似。为了清晰起见,我添加了评论。

  // Set x to some array literal
> x = [1, 2, 3, 4, 5]
  [1, 2, 3, 4, 5]

  // Set y to x
> y = x
  [1, 2, 3, 4, 5]

> x
  [1, 2, 3, 4, 5] // as expected

> y
  [1, 2, 3, 4, 5] // as expected

如上所示,xy都输出了预期值。现在我使用一个名为shuffle的函数(在本问题的底部指定)对x的值进行洗牌。

  // Shuffle x
> x = shuffle(x)
  [5, 1, 4, 2, 3]

> x
  [5, 1, 4, 2, 3] // x changes as expected

> y
  [5, 1, 4, 2, 3] // y changes as expected

同样,一切都按预期工作。变量xy保持对同一对象的引用。但是,当我们重复这个操作时,结果很奇怪。

  // Shuffle x
> x = shuffle(x)
  [3, 1, 5, 4, 2]

> x
  [3, 1, 5, 4, 2] // x changes as expected

> y
  [5, 1, 4, 2, 3] // y didn't change this time

以下是改编自here的随机播放功能。其目的是对数组的内容进行混洗(参数r1)并返回混合数组的第一个n项。

function shuffle(r1,n) {

  var i = r1.length, j, tempi, tempj, r2;
  r2 = r1;

  while (--i) {
    j = Math.floor(Math.random() * (i + 1));
    tempi = r2[i];
    tempj = r2[j];
    r2[i] = tempj;
    r2[j] = tempi;
  }

  return r2.slice(0,n);
}

我已经通过重写基于this function的shuffle函数来解决问题。但是,我仍然想了解发生了什么。为了快速查看代码的实际运行情况,我制作了jsFiddle

有什么想法吗?我很感激你的时间。

2 个答案:

答案 0 :(得分:4)

如果删除.slice(0,n);,它将按照您的预期行事。 slice创建了一个新数组。

因此,第一次调用shuffle时,在循环中修改数组x = y = r1 = r2。然后在最后一行上复制它并将其分配给x。现在x !== y,但它们包含完全相同的元素。第一次打电话后你可以test that they are distinct objects :.

下次你打电话给shuffle时,你正在洗牌x的副本,y未被触及。

答案 1 :(得分:3)

.slice()生成数组的浅表副本,因此您使用新数组覆盖x

// The original was shuffled, but now `x` is a new Array
x = shuffle(x);

这就是为什么y显示第一个shuffle (因为你还没有切片),但之后没有。随后的随机播放被覆盖x,而y仍然引用了原始内容。


如果要截断原始数组,只需更改其.length

所以不要这样:

return r2.slice(0,n);

这样做:

r2.length = n;

...虽然你目前没有向n传递任何内容。