面试:JavaScript 中常考的一些数组方法

93 阅读5分钟

一、修改原数组的方法(有副作用)

这类方法会直接修改原始数组的结构或内容,可能导致副作用,一般适合需要动态调整数组的场景(如队列、动态更新),但需谨慎使用以避免意外数据污染。

1. 栈/队列操作

push(...items) / pop()

  • 作用push 向数组末尾添加元素并返回新长度;pop 删除最后一个元素并返回该元素。
  • 副作用:直接修改原数组。
  • 适用场景:实现栈(先进后出)或队列(先进先出)逻辑。
    const arr = [1, 2];
    arr.push(3); // [1, 2, 3]
    arr.pop();   // 3, arr 变为 [1, 2]
    

shift() / unshift(...items)

  • 作用shift 删除第一个元素;unshift 向开头添加元素。
  • 副作用:修改原数组,但性能较差(需移动元素)。
  • 适用场景:需频繁操作数组头部时(慎用)。
    const arr = [1, 2];
    arr.unshift(0); // [0, 1, 2]
    arr.shift();    // 0, arr 变为 [1, 2]
    

2. 灵活的数组操作

splice(start, deleteCount, ...items)

  • 作用:删除或替换数组元素,并返回被删除的元素。
  • 副作用:直接修改原数组。
  • 适用场景:动态调整数组内容(如删除中间元素、插入新数据)。
    const arr = [1, 2, 3, 4, 5];
    const removed = arr.splice(2, 2); // 删除索引2开始的2个元素
    console.log(removed); // [3, 4]
    console.log(arr);     // [1, 2, 5]
    

3. 排序与反转

sort([compareFunction])

  • 作用:对数组元素进行排序。
  • 副作用:修改原数组。
  • 注意事项
    • 默认按字符串字典序排序(可能不符合预期)。
    • 需通过 a - b 实现数字升序,b - a 降序。
    const arr = [3, 1, 4];
    arr.sort((a, b) => a - b); // [1, 3, 4]
    

reverse()

  • 作用:反转数组元素顺序。
  • 副作用:修改原数组。
    const arr = [2, 4, 3, 1, 5];
    arr.reverse(); // [5, 1, 3, 4, 2]
    

4. 填充数组

fill(value, start, end)

  • 作用:用指定值填充数组区间。
  • 副作用:修改原数组。
  • 适用场景:初始化固定值数组或批量更新数据。
    const arr = [5, 1, 4, 2, 3];
    arr.fill(9, 1, 3); // [5, 9, 9, 2, 3]
    

二、不修改原数组的方法(纯函数)

相较于上文所述,下面这些方法则不会改变原始数组,而是返回新数组或值,属于无副作用的“纯函数”,一般适合用于数据转换、过滤和聚合,保持数据不可变性,减少调试复杂度。

1. 遍历与转换

forEach(callback)

  • 作用:对数组每个元素执行回调,无返回值。
  • 特点:不返回新数组,适合副作用操作(如渲染 DOM)。
    const arr = [1, 2, 3];
    arr.forEach(item => console.log(item)); // 输出 1, 2, 3
    

map(callback)

  • 作用:对数组每个元素执行回调,返回新数组。
  • 适用场景:数据格式转换(如将字符串转数字)。
    const arr = ["1", "2", "3"];
    const nums = arr.map(Number); // [1, 2, 3]
    

2. 筛选与聚合

filter(callback)

  • 作用:筛选满足条件的元素,返回新数组。
  • 适用场景:过滤无效数据(如移除空值)。
    const arr = [1, 2, 3, 4];
    const even = arr.filter(x => x % 2 === 0); // [2, 4]
    

slice(start, end)

  • 作用:截取数组片段,返回新数组。
  • 适用场景:提取子数组而不修改原数组。
    const arr = [1, 2, 3, 4, 5];
    const subArr = arr.slice(0, 2); // [1, 2]
    

3. 查找与判断

find(callback) / findIndex(callback)

  • 作用:查找满足条件的第一个元素或其索引。
  • 适用场景:快速定位特定对象(如查找用户信息)。
    const users = [
      { id: 1, name: "Alice" },
      { id: 2, name: "Bob" }
    ];
    const user = users.find(u => u.id === 2); // { id: 2, name: "Bob" }
    

includes(value)

  • 作用:判断数组是否包含某值。
  • 适用场景:验证权限或数据存在性。
    const arr = [1, 2, 3];
    arr.includes(2); // true
    

三、业务场景中的最佳实践

在实际开发中,还是要根据业务需求选择合适的方法,平衡性能、以此维护性和数据一致性,如:在数据展示前使用纯函数方法预处理数据,在动态更新时使用修改原数组的方法。

1. 避免副作用的场景

  • 推荐方法mapfilterslice
  • 案例:数据展示前的预处理。
    const data = [10, 20, 30];
    const processed = data.map(x => x * 2); // [20, 40, 60]
    // data 仍为 [10, 20, 30]
    

2. 性能敏感的场景

  • 慎用方法shiftunshift
  • 替代方案:使用 slice + concat 模拟队列。
    const queue = [1, 2, 3];
    const newQueue = [queue[0] + 1].concat(queue.slice(1)); // [2, 2, 3]
    

3. 数据清洗的场景

  • 推荐方法filter + map
  • 案例:过滤空值并转换格式。
    const raw = [null, "a", undefined, "b"];
    const clean = raw.filter(Boolean).map(x => x.toUpperCase()); // ["A", "B"]
    

四、版本演进与兼容性

1. ES5 vs ES6+

  • ES5:提供 indexOflastIndexOf 等基础查找方法。
  • ES6:新增 findincludes 等更直观的方法。
  • ES2023:引入 findLastfindLastIndex,增强反向查找能力。

2. 兼容性建议

  • 生产环境:优先使用 includes 替代 indexOf 判断存在性。
  • 旧浏览器:通过 Polyfill 补充缺失方法(如 Array.from)。

五、总结

方法类型推荐方法适用场景是否修改原数组
修改原数组push/pop/splice/sort动态调整数组内容(如队列操作)
纯函数map/filter/slice数据转换/过滤(保持数据不可变)
查找与判断find/includes快速定位或验证数据存在性

建议

  • 在需要保持数据不可变时,优先选择不修改原数组的方法。
  • 对性能敏感的场景(如大型数组),避免使用 shift/unshift
  • 结合业务需求选择合适的方法,例如:map 转换数据、filter 清洗数据、find 定位关键元素。