在刷 leetcode
时,有时候需要二维数组来存数据,那对于不是强类型语言的JS
,应该怎么声明和初始化一个二维数组呢?
可能你会想到通过一个一维数组数组来fill
一个一维数组来实现👇 因为我一开始也是这么写的😄
const arr = new Array(2).fill(new Array(2).fill(0));
console.log("arr: ", arr);
// arr: [ [ 0, 0 ], [ 0, 0 ] ]
arr[0][0] = 1;
console.log("arr: ", arr);
// arr: [ [ 1, 0 ], [ 1, 0 ] ]
但这是不对的,你确实是声明和初始化了一个二维数组,但当你想要修改二维数组中的某个元素时(比如arr[0][0]
),会修改第1
列的所有元素
MDN
上对fill
的部分描述如下
fill(value)
Value to fill the array with. Note all elements in the array will be this exact value: if value is an object, each slot in the array will reference that object.
意思就是fill
的值是一个exact value
, 如果你传值那就是精确的值,没什么问题,但如果你传一个引用数据类型,比如数组和对象,那这个数组中的每一个fill
的地方都将引用这个数据,fill
的其实是地址
所以fill
用来初始化值很好,但是构建二维数组这个工作就别让他干了
关于fil
l方法,还有一个点需要注意的是,在空数组(length = 0
)上使用fill
是没用的,因为数组没有什么可修改的。所以如果你要用fill
,那就写上数组的长度
# fill + map
正确的声明和初始化方法就是fill
配合map
,初始化用fill
,声明用map
const arr = new Array(2).fill(0).map(() => new Array(2).fill(0));
console.log("arr: ", arr);
// arr: [ [ 0, 0 ], [ 0, 0 ] ]
arr[0][0] = 1;
console.log("arr: ", arr);
// arr: [ [ 1, 0 ], [ 1, 0 ] ]
先new
出来一个一维数组(对应二维数组的行),然后map
把数组中的每一项用一个一维数组返回(对应二维数组的列)
# Array.from + fill
利用Array
的静态方法from
来实现
MDN
上的描述👇
The Array.from() static method creates a new, shallow-copied Array instance from an iterable or array-like object.
把一个类数组对象或可迭代对象浅复制成一个新的正儿八经的Array
const arr = Array.from(new Array(2), () => Array(2).fill(0))
console.log("arr: ", arr);
// arr: [ [ 0, 0 ], [ 0, 0 ] ]
arr[0][0] = 1;
console.log("arr: ", arr);
// arr: [ [ 1, 0 ], [ 1, 0 ] ]
from
的第一个参数就是要操作的类数组对象或者可迭代对象(对应二维数组的行)
第二个参数传入一个回调,要添加到最后的数组中的每个值都将首先执行该回调,返回值添加到正儿八经的Array
中(对应二维数组的列)