解决JS使用fill()进行数组填充遇到的问题
本文深入解析JavaScript中Array.fill()方法在创建二维数组时的常见陷阱。通过对比错误写法与正确写法,阐明对象引用传递机制导致的共享引用问题,并详细介绍fill()的语法、参数、原地修改特性及负索引用法,帮助开发者避免测试用例失败。
前言:
最近在做算法题时,遇到需要创建二维数组并进行初始化的情况,刚开始我使用的是 new Array(n).fill(new Array(n).fill('.')) 进行二维数组的初始化,但无论怎样我都通不过测试用例。这让我十分纳闷,无奈之下,只能对照着标准代码一句一句排查,终于让我找到了罪魁祸首:Array(n).fill(new Array(n).fill('.'))。我将Array(n).fill(new Array(n).fill('.'))改成new Array(n).fill(0).map(\_ => new Array(n).fill('.'))之后,用例通过了。
接下来,我们将通过对比这两段代码,重新学习 JavaScript 中的 fill() 方法,以避免未来出现类似错误。
两句代码之间的区别
相同点:上述两种代码的目标都是创建一个 n x n 的二维数组,但它们的实现方式和最终结果存在显著差异。
不同点
let board = new Array(n).fill(new Array(n).fill('.'));这段代码在填充数组时,使用了同一个
数组实例(通过 new Array(n).fill('.')创建)。这会导致生成的数组中每个元素都指向同一个数组实例(即修改其中一个子数组,所有子数组都会随之改变)。这是因为在 JavaScript 中,对象(包括数组)是通过引用传递的。const board2: string[][] = new Array(n).fill(0).map(\_ => new Array(n).fill('.'));
这段代码利用 .map() 函数生成了 n 个独立的数组实例。这意味着每个子数组都是相互独立的,修改其中一个不会影响其他子数组。这是因为 .map() 会对原数组的每个元素执行回调函数,而回调函数内部创建了一个全新的数组。
因此,尽管这两段代码在表面上都旨在创建 n x n 的二维数组,但它们在数组引用的管理和修改行为上有着本质的不同。
为什么会造成这样的结果呢?
首先,我们尝试手动实现一下 fill 方法:
Array.prototype.fill = function(value, start = 0, end = this.length) {
// Handle negative values for start
if (start < 0) {
start += this.length;
if (start < 0) start = 0;
}
// Handle negative values for end
if (end < 0) {
end += this.length;
}
// Ensure start is not greater than end
if (start > end) {
[start, end] = [end, start];
}
// Fill the array
for (let i = start; i < end; i++) {
this[i] = value;
}
return this;
};从实现可以看出,fill 方法直接将 value 的值赋给数组的每一项,并且会修改原数组的值。
注意:这个手动实现并未处理边缘情况和错误检查,因此并非完全准确的实现。真实的 Array.prototype.fill() 方法更为复杂,需要处理各种边缘情况和错误条件。
因此,当我们传入一个引用类型时,数组中的每一项都指向同一个对象。这意味着修改其中一个元素,所有元素都会受到影响。在使用 .fill() 方法填充数组时,需特别注意这一特性。
fill 方法其他需要注意的地方:
语法:
arr.fill(value ,[start],[end]) 参数:
- value:用于填充数组的值。
- start(可选):开始填充数组的索引。默认为 0。
- end(可选):停止填充数组的索引。默认为 arr.length。
- 返回值:被修改后的数组,从 start 到 end 被 value 填充。
原地操作
fill() 是一个原地操作,这意味着它会 直接修改原始数组,而不是创建一个新的数组。这与 JavaScript 中的许多其他数组方法(如 map() 或 filter())不同,后者会返回新数组并保持原始数组不变。
负索引
fill() 方法也接受 负索引,它们从数组的末尾开始计算。例如,-1 指的是最后一个元素,-2 指的是倒数第二个元素,等等。如果你对 start 或 end 参数使用负索引,fill() 将从 数组末尾 开始或停止填充。
兼容性:
所有现代浏览器中都受支持,但在 Internet Explorer 中不受支持。 如果你需要支持旧版浏览器,你可能需要使用 polyfill 或者其他方式来实现相同的功能。
总结:
通过这两段代码的对比,我获益匪浅。虽然排查问题花费了一些时间,但最终结果令人满意。今天的分享就到此为止,如有错误之处,欢迎大家留言指出,谢谢大家。
到此这篇关于解决JS使用fill()进行数组填充遇到的问题的文章就介绍到这了,更多相关JS fill()数组填充内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
D3.js 比例尺与坐标轴的配置详解
2026-11-05 16:54:46
JavaScript怎么遍历对象的Symbol键和不可枚举属性
2026-11-05 13:13:39
封装一个健壮的JS字符串判空工具函数
2026-11-05 12:16:14
JavaScript合并数组的三种常用方法:concat、扩展运算符与push
2026-11-05 11:22:29
JavaScript立即执行函数(IIFE)是什么及基本语法
2026-11-05 10:51:19
