哪些数组方法会改原数组?类数组怎样转成真正的数组?

先理解原理和示例,再练习完整口述与追问。

push、pop、shift、unshift、splice、sort、reverse、fill、copyWithin 修改原数组。map、filter、slice、concat 返回新数组。ES2023 的 toSorted、toReversed、toSpliced、with 是不修改原数组的版本。类数组有下标和 length,用 Array.from 或展开转换;Array.from 会把空位填成 undefined,map 会保留空位。

会修改原数组的方法适合就地算法和内存敏感的场景,但共享给界面状态时会造成难以追踪的修改。React、Vue 的状态更新更适合用返回新数组的方法。sort 和 reverse 返回的是原数组本身,不是副本;比较函数必须返回数字。ES2019 起 sort 必须稳定,V8 使用 TimSort,见宝典 66。

类数组包括 arguments、DOM 的 NodeList(旧集合)、以及 { 0: 'a', length: 1 } 这种对象。它们没有数组原型上的 map。Array.from(arrayLike, mapFn) 按 length 读取下标,第二个参数相当于映射且不会跳过空位。可迭代对象,例如 Set、Map 的键、字符串,用 Array.from 或展开都会按迭代器取值。字符串展开按码点,见下一题。

js
const values = [3, 1, 2]
const same = values.sort((a, b) => a - b)
console.log(same === values, values) // true [1, 2, 3]

const holes = [, 1]
console.log(0 in holes.map(value => value), 0 in Array.from(holes)) // false true
console.log(Array.from({ 0: 'a', length: 1 })) // ['a']
console.log(Array.from(new Set([1, 1, 2]))) // [1, 2]

toSorted 需要较新的运行时,目标环境不支持时要转译或继续先复制再 sort。document.querySelectorAll 的结果是静态 NodeList,现在一般可迭代,但不是数组。不要用 for...in 遍历数组下标。

push、pop、shift、unshift、splice、sort、reverse、fill、copyWithin 会改原数组,sort 和 reverse 返回的也是原数组。map、filter、slice、concat 以及 toSorted、toReversed、toSpliced、with 返回新数组。类数组只有下标和 length,转换用 Array.from 或展开。Array.from 会把空位变成显式的 undefined,map 则保留空位。Set 和 Map 这些可迭代对象也能交给 Array.from。