函数调用为何影响前置操作?JavaScript数组Shuffle问题咨询
为什么两次
console.log都输出打乱后的数组? 哦,这个问题我太熟了——本质上是数组作为引用类型的特性,再加上你的Shuffle函数大概率是「原地修改原数组」的实现,才会出现这种反直觉的情况。咱们一步步拆解:
1. JavaScript里的数组是引用类型
你定义的Words变量,存的并不是数组里的每一个元素,而是一个指向内存中实际数组数据的「引用地址」。简单说,Words就像一个门牌,指向存放数组的房间,而不是房间本身。
2. 你的Shuffle函数在“拆原房间”
几乎所有新手写洗牌函数时,都会犯这个错:直接在输入的数组上做元素交换,而不是创建一个新数组来打乱。比如你可能写了类似这样的代码:
function Shuffle(Input_array) { // 直接修改传入的原数组! for (let i = Input_array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [Input_array[i], Input_array[j]] = [Input_array[j], Input_array[i]]; } return Input_array; // 返回的还是原数组的引用 }
当你调用Shuffle(Words)时,函数直接找到了Words指向的那个“房间”,把里面的元素重新打乱了,最后返回的还是同一个房间的门牌——也就是说,Shuffle(Words)和Words指向的是同一个数组。
3. 控制台的“实时快照”坑了你
你以为先console.log(Words)打印的是原数组,再调用Shuffle后打印打乱后的,但浏览器控制台对引用类型的输出有个特殊行为:它显示的不是打印那一刻的静态快照,而是当你展开数组时,去读取当前内存中的数组状态。
所以流程是:
- 你执行
console.log(Words),控制台记录了这个数组的引用,但没立刻展示内容; - 你调用
Shuffle(Words),原数组被打乱; - 你去控制台看输出,展开第一次打印的数组,它会读取已经被打乱的数组状态,所以看起来两次都是打乱后的。
而当你注释掉最后一条console.log时,Shuffle根本没被调用,原数组没被修改,控制台打印的就是初始状态的数组。
怎么解决?
有两个靠谱的方案:
- 方案一:让
Shuffle返回新数组
先复制原数组的副本,在副本上打乱,原数组完全不受影响:function Shuffle(Input_array) { // 用扩展运算符创建原数组的浅拷贝 const shuffledArr = [...Input_array]; for (let i = shuffledArr.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffledArr[i], shuffledArr[j]] = [shuffledArr[j], shuffledArr[i]]; } return shuffledArr; // 返回新数组,和原数组无关 } - 方案二:打印时生成静态快照
如果一定要原地打乱数组,那在打印原数组时,先把它转成静态的副本或者字符串:// 打印原数组的副本 console.log([...Words]); // 或者转成字符串,完全静态 console.log(JSON.stringify(Words));
内容的提问来源于stack exchange,提问作者Speldosa
相关产品推荐
相关产品推荐

