从 PHP 转过来写 JS,想初始化一个长度为 5 的数组,顺手写了 new Array(5),后面接 map 填默认值,结果回调一次都没跑。

new Array(5) 建出来的是 5 个空槽,不是 5 个 undefined。map、forEach、filter 都会跳过空槽,所以看起来什么都没发生。要初始化就用 Array(5).fill(0),或者 Array.from({length:5}, (_, i) => i)。

二维数组别用 fill 填对象

Array(3).fill([]) 里那三行是同一个数组的引用,改一行三行一起变。正确写法是 Array.from({length:3}, () => [])。生成表格数据时特别容易中招,表现是编辑任意一行,其他行跟着变,排查半天才发现是引用共享。

各语言声明时的默认值

  • Java:int[] a = new int[5] 元素默认 0,String[] 默认 null,长度固定,扩容用 Arrays.copyOf
  • C:int a[5] 在栈上不初始化就是脏值,写 = {0} 或 memset 才干净,malloc 出来的要 free
  • Python:list 可以动态增长,[0]*5 对数字安全,[[0]*3]*2 两行共享引用
  • PHP:数组是有序映射,键可以是字符串,初始化用 [] 或 array_fill(0, 5, 0)
  • Go:var a [5]int 是零值数组,make([]int, 5) 是长度 5 的切片

长度计算的两个坑

C 里 sizeof(a)/sizeof(a[0]) 只在数组还在当前作用域时有效,传进函数后退化成指针,算出来是 8 除以 4 得 2。JS 的 length 是最大索引加一,删掉中间元素不会变,用 delete 还会留下空槽。

还有一点,空槽和 null 不一样。JSON.stringify 会把空槽变成 null,但 Object.keys 里看不到它,用 in 判断也返回 false。接口返回的数组如果有空槽,前端遍历时容易漏项。

声明语法只是外壳,真正决定行为的是容器语义:定长还是动态、零值还是未初始化、引用共享还是各自独立。写之前想清楚这三点,比背语法管用。