为何嵌套数组声明方式不同会导致push出现异常结果?
直接声明
[[],[],[],[]]的本质
这种写法里的每一个[]都是单独创建的全新数组实例,彼此的内存引用完全独立。当你对某一个子数组执行push时,只会修改对应实例的内容,其他子数组不受影响,自然能得到预期结果。new Array(4).fill([])的坑点fill方法的逻辑是把传入的参数值赋值给数组的每一个位置。这里传入的[]是一个数组实例,fill会把这个实例的引用复制到新数组的4个位置上。也就是说,这4个“子数组”其实是同一个数组的不同别名——不管你操作哪一个,本质上都是在修改同一个底层数组。所以执行push时,所有位置看起来都被填充了相同内容,因为它们本来就是同一个东西。为什么
concat方法都能正常工作concat和push的核心区别在于:push是直接修改原数组,而concat会返回一个新的数组实例,不会改动原数组。
不管是哪种方式创建的嵌套数组,当你执行arr[i] = arr[i].concat(xxx)时,都会把当前位置替换成concat生成的新数组。对于fill创建的数组来说,这一步相当于把原来共享的引用替换成了独立的新数组,最终每个位置都是各自独立的实例,所以结果符合预期。控制台显示“看似一致”的原因
浏览器控制台对数组的显示是惰性展开的:一开始只会显示数组的结构(比如[Array(0), Array(0), ...]),只有当你点击展开箭头时,才会去读取数组的当前实际内容。对于fill创建的数组,初始时每个位置的引用指向的是空数组,所以展开前看起来和直接声明的数组一样;但当你执行push修改后,展开时读取的是这个共享数组的最新状态,就会显示所有位置都有内容了。
内容的提问来源于stack exchange,提问作者Jimbo

