持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
前言
前几天在刷
leetcode的时候,有一道题需要创建一个二维数组(长宽相等的矩阵),于是写下了如下的代码
function createMatrix(n: number) {
return Array(n).fill([]);
}
不知道各位小伙伴觉得这样创建矩阵的方式有问题吗 ?
Array.prototype.fill 问题
const matrix = createMatrix(5);
控制台打印的结果:
这么看似乎真的是创建成功了,但是在使用的时候就出现了大问题
我们想要给矩阵中的 任意一项 赋值
matrix[1][1] = 10;
在控制台的结果:
结果是 给矩阵中的每个数组索引为 1 的都赋上值了
大家发现问题在哪里的了吗
没发现的的小伙伴不用着急,可以对比这一种创建矩阵的方式
const matrix = [
[],
[],
[],
[],
[],
];
这时候,细心的小伙伴就会发现,这里的矩阵中的数组是 不同的数组实例
原来如此,使用 fill 创建的矩阵中的五个数组其实都指向 同一个实例
const matrix = createMatrix(5);
matrix[0] === matrix[1]; // true
当一个对象被传递给
fill方法的时候,填充数组的是这个对象的引用 -- mdn
const arr = Array(3).fill({}) // [{}, {}, {}];
// 需要注意如果 fill 的参数为引用类型,会导致都执行同一个引用类型
// 如 arr[0] === arr[1] 为 true
当 fill 第一个参数是引用值 的时候,分发给数组每一项的值都是这个引用值的 指针,所以我们修改 [] 都是修改同一个实例
第二个巨坑 - 数组空位
我们知道了使用直接使用 fill 创建矩阵的问题了
解决办法:遍历数组的每一项,单独给每一项赋值独立的数组实例
于是写下如下代码:
function createMatrix(n: number) {
return Array(n).map(() => []);
}
这次大家觉得能成功的创建矩阵吗
const matrix = createMatrix(5);
控制台打印的结果:
好家伙,这次连一项都不创建,为什么会有这个问题呢?
结论:Array.prototype.map 遍历数组会忽略 empty 项
数组中的 empty 就是我们常说的数组空位,代表没有任何值。
arr[0] === undefined; // true
尽管 empty 与 undefined 看起来相等 ,但是下面的例子可以很明显看出它们的差异
0 in Array(5); // false
0 in [undefined, undefined, undefined, undefined, undefined]; // true
对于数组空位的差异,ES6之前 会忽略掉空位,而 ES6之后 的方法会当做 undefined 处理,例如
// join 方法忽略空位
[1, , , 5].join('-'); // 1---5
// ... 扩展运算符将空位当做undefined
Array.of(...[, , ,]); // [undefined, undefined, undefined]
由于空位的处理规则非常不统一,所以我们应该避免处理空位。
优雅地创建二维数组(矩阵)
两种思路:
- 使用循环 / 遍历,逐项创建数组实例
Array工厂函数,使用ES6之后的方法避免处理数组空位
- 将数组空位填充为真实存在的内容
function createMatrix(n: number) {
return Array(n)
.fill(0)
.map(() => []);
}
- 使用 ES6 之后的方法处理数组空位
function createMatrix(n: number): number[][] {
return Array.from(Array(n), () => []);
}
function createMatrix(n: number): number[][] {
return Array.of(...Array(n)).map(() => []);
}