js fill填充数组
JS 数组 fill 方法:高效初始化背后的“引用陷阱”
做前端开发时,我们常遇到这种场景:需要初始化一个长度为 10 的数组,里面全是 0,或者全是空对象。新手习惯写 for 循环,老手会想到 new Array(10).fill(0)。这行代码看似简洁优雅,实则藏着不少容易忽视的细节,一旦用错,排查起 Bug 来十分头大。
基础用法与参数细节
Array.prototype.fill() 的核心作用很简单:将数组中指定范围的内容替换为一个固定值。语法是 arr.fill(value[, start[, end]])。其中 value 必传,start 和 end 可选,默认从头填到尾。
最实用的地方在于它对负索引的支持。比如你想把数组最后 3 个元素置为 null,无需计算长度,直接写 arr.fill(null, -3) 即可生效。此外,范围也是左闭右开,这与切片操作 slice 保持一致,符合大多数开发者的直觉。
const arr = new Array(5).fill(0);
// [0, 0, 0, 0, 0]
致命的“引用陷阱”
这才是这篇文章的重点。当 fill 的值是基本类型(如数字、字符串)时,没问题;但如果是对象或数组,所有元素将共享同一块内存地址。
很多开发者在初始化二维数组或对象列表时踩过的最大坑就在这里。比如下面这段代码:
const matrix = new Array(3).fill({ val: 0 });
matrix[0].val = 100;
console.log(matrix);
// 输出:[{val: 100}, {val: 100}, {val: 100}]
你以为只是修改了第一个元素的属性,结果整个矩阵都变了。这是因为 fill 执行的是浅拷贝,三个位置存的都是同一个对象的引用。想要独立修改每个格子,必须配合 map 使用,确保每次生成新实例:
const safeMatrix = new Array(3).fill(0).map(() => ({ val: 0 }));
变性与替代方案
另一个常被忽略的特性是原地修改。fill 不会返回新数组,而是直接改变原数组并返回该数组引用。如果你期望像函数式编程那样保持数据不可变性,这个方法就需要谨慎对待。
相比手动循环,fill 的优势在于可读性和性能优化。现代浏览器对内置方法的底层优化远优于手写循环。但在处理复杂结构时,它并非万能钥匙。例如创建 [1, 2, 3] 这样的递增序列,fill 无能为力,这时候应该转而使用 Array.from({ length: 3 }, (_, i) => i + 1),既避免了引用问题,又能实现动态值的生成。
实际开发建议
在日常工作中,判断是否使用 fill 可以参考以下思路:
- 值类型优先:如果填充内容只是数字、布尔值或
null,放心大胆用,效率最高。 - 对象需谨慎:只要涉及对象、数组等引用类型,务必检查是否需要独立副本。
- 链式搭配:常与
map组合使用,先定长度,再映射值,逻辑更清晰。
掌握 fill 的真正意义,不在于记住它的语法,而在于理解它如何处理内存中的“引用”。避开那个简单的对象陷阱,能让你的代码在初始化阶段就干净稳定得多。


还没有评论,来说两句吧...