JavaScript 二维数组初始化:为什么 fill([]) 是个大坑?

JavaScript 二维数组初始化:为什么 fill([]) 是个大坑?

今天刷leetcode的时候,遇到一个神奇的bug。

当我修改数组中的一个元素,却意外影响了其他所有元素???。

问题重现:诡异的数组共享

ini 复制代码
const r = 3;
const mat = new Array(r).fill([]);
mat[0].push(1);
console.log(mat); // 输出什么?

我期望的输出可能是 [[1], [], []],但实际结果却是 [[1], [1], [1]]!所有子数组都被修改了。

为什么会这样???

引用类型的陷阱

在 JavaScript 中,数组是引用类型。当我们使用 fill([]) 时:

  1. 首先创建一个空数组 [](假设内存地址为 0x123)
  2. 然后将这个引用复制到新数组的每个位置

内存结构如下:

markdown 复制代码
mat: [0x123, 0x123, 0x123]  
      │      │      │  
      ▼      ▼      ▼  
    [ ]    [ ]    [ ]  

所有元素都指向同一个数组对象!

与原始类型的区别

对比使用原始类型的情况:

javascript 复制代码
const arr = new Array(3).fill(0);
arr[0] = 1;
console.log(arr); // [1, 0, 0] 表现正常

因为原始类型(如数字)是直接存储值,而非引用。

正确的初始化方式O(∩_∩)O~

方法1:循环初始化

javascript 复制代码
const mat = new Array(r);
for (let i = 0; i < r; i++) {
    mat[i] = [];
}

方法2:使用 map(推荐)

javascript 复制代码
const mat = new Array(r).fill().map(() => []);

或者更简洁的:

javascript 复制代码
const mat = Array.from({ length: r }, () => []);

总结

  1. 永远不要用 new Array(n).fill([]) 初始化二维数组
  2. 引用类型在 fill() 中会被共享
  3. 使用 Array.frommap 确保每个子数组独立

啊啊啊啊啊哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇

相关推荐
加班是不可能的,除非双倍日工资4 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi4 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip5 小时前
vite和webpack打包结构控制
前端·javascript
excel5 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国5 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼5 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy5 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT6 小时前
promise & async await总结
前端
Jerry说前后端6 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化
画个太阳作晴天6 小时前
A12预装app
linux·服务器·前端