我试图理解我对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
如上所示,x
和y
都输出了预期值。现在我使用一个名为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
同样,一切都按预期工作。变量x
和y
保持对同一对象的引用。但是,当我们重复这个操作时,结果很奇怪。
// 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。
有什么想法吗?我很感激你的时间。
答案 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
传递任何内容。