数组中的对象是否按引用传递?解析洗牌函数中oldValue变量未随数组元素引用变更而改变的原因
关于JavaScript引用传递的两个疑问解答
嘿,我来帮你把这两个点掰明白——很多刚接触JS对象引用的朋友都会在这里卡壳,咱们一步步来:
1. 数组中的对象是否是按引用传递的?
首先得纠正一个常见误区:JavaScript里不存在真正的“按引用传递”,只有“按值传递”。不过对于对象(包括数组、普通对象)来说,这个“值”其实是指向内存中对象的引用地址。
所以数组里存储的并不是对象本身,而是对象的引用地址。当你把数组中的对象赋值给另一个变量,或者把数组作为参数传给函数时,传递的是这个引用地址的副本——也就是说,两个变量(或参数)会指向同一个对象,但它们本身是独立的变量,各自存着相同的引用值。
举个简单例子:
const arr = [{name: 'Alice'}]; const obj = arr[0]; obj.name = 'Bob'; console.log(arr[0].name); // 输出 'Bob'
这里obj和arr[0]都指向同一个对象,所以修改obj的属性会影响数组里的对象,但如果你给obj重新赋值一个新对象:
obj = {name: 'Charlie'}; console.log(arr[0].name); // 还是 'Bob',因为obj现在指向新对象,和arr[0]没关系了
2. 为什么洗牌代码里的oldValue没有跟着cards[newIndex]变化?
咱们盯着你的代码一步步拆解:
function shuffle(cards) { for (let i = cards.length - 1; i > 0; i --) { const newIndex = Math.floor(Math.random() * (i + 1)); const oldValue = cards[newIndex]; // 这一步:oldValue拿到的是cards[newIndex]当前存储的引用地址(比如指向{ suit: 'clubs', value: '5' }) cards[newIndex] = cards[i]; // 这一步:把cards[newIndex]这个数组位置的引用地址,换成了cards[i]的引用地址 // 注意:这只是修改了数组里这个位置存的“地址纸条”,和oldValue手里的“地址纸条”没关系! } }
你可以把引用地址想象成写着房间号的纸条:
- 数组的每个位置就像一个盒子,里面装着一张写着房间号的纸条。
oldValue = cards[newIndex]就是把盒子里的纸条抄了一份,oldValue现在手里有一张一模一样的纸条。- 然后你把盒子里的纸条换成了另一张(
cards[newIndex] = cards[i]),但oldValue手里的那张抄件根本没动,它还是指向原来的房间。
所以oldValue不会跟着变化,因为它和数组的那个位置是两个独立的“容器”,只是曾经装过相同的引用地址而已。
总结一下:变量存储的是引用的副本,修改另一个容器里的引用,不会影响已经拷贝出去的引用值——只有当你通过引用修改对象本身的属性时,所有指向这个对象的变量才会看到变化。
内容的提问来源于stack exchange,提问作者PRMK
相关产品推荐
相关产品推荐

