JavaScript中fill与循环创建矩阵行为差异原因探究
为什么用
Array.fill创建矩阵和循环创建的行为差这么多? 哈哈,这个问题我当初刚学JS的时候也踩过一模一样的坑!先看你遇到的情况:
// 用.fill创建矩阵 var aMatrix = new Array(5).fill(new Array(5)); aMatrix[0][0] = 'X'; // 结果所有行的第0个元素都变成了'X' console.log(aMatrix);
为啥会出现这种“牵一发而动全身”的情况?核心问题出在Array.fill对引用类型的处理上,咱们一步步掰扯清楚:
罪魁祸首:引用类型的复用
JavaScript里的数据类型分两种:原始类型(比如数字、字符串、null)和引用类型(比如数组、对象)。当你把引用类型传给Array.fill()的时候,它不会给数组的每个位置都创建一个新的实例——而是把同一个引用复制到了每一个位置。
换句话说,你创建的aMatrix里的5个“行”,其实全都是指向同一个数组对象的指针!所以你修改aMatrix[0][0]的时候,本质上是在修改那个唯一的底层数组,自然所有行都会跟着同步变化。
循环创建为啥就没问题?
如果换成循环的方式:
var aMatrix = []; for (let i = 0; i < 5; i++) { aMatrix.push(new Array(5)); // 每次循环都new一个新数组 } aMatrix[0][0] = 'X'; console.log(aMatrix); // 只有第一行的第0个元素是'X'
这里每次循环都会调用new Array(5),生成一个全新的数组实例,然后把这个新数组的引用加到aMatrix里。每一行都是独立的个体,修改其中一行完全不会影响其他行。
想用fill又不想踩坑?这样写就行
如果还是喜欢fill的简洁写法,可以结合map来规避引用复用的问题:
var aMatrix = new Array(5).fill(null).map(() => new Array(5)); aMatrix[0][0] = 'X'; console.log(aMatrix); // 正常只有第一行变
先拿fill(null)填充(null是原始类型,不存在引用共享的问题),然后用map遍历每个位置,返回一个新的数组实例。这样每一行都是独立的,完美解决问题。
最后再划个重点
- 用
Array.fill填充引用类型时,数组所有位置共享同一个引用,修改一处全变; - 循环创建矩阵时,每次生成新的实例,各行相互独立;
- 想兼顾
fill的简洁和正确性,就用fill + map的组合。
内容的提问来源于stack exchange,提问作者Vaibhav Arora
相关产品推荐
相关产品推荐

