前端面试之——JavaScript数组方法

面试的时候问的es6+ 有哪些部分也很多,我们可以往准备方面回答,比如数组方法就是一个秀肌肉的好地方。也别一开始就Array.of,Array.from,map什么的,人家已经听一天这种开头了。当然要答,分层面的答,不是不答,让其他先答带动这个后答,只有先答的亮了,后答才更吸引人。

会修改原数组的方法

会修改原数组的方法也被称为非纯函数,因为它们会产生副作用。慎用!!!(实用层面吸引面试官)

push/pop/shift/unshift:栈和队列操作

这些最基础方法用于数组添加或删除元素:

javascript 复制代码
let arr = [1, 2, 3];

arr.push(4); // 在末尾添加元素,返回新长度:4

arr.pop(); // 删除末尾元素,返回被删除的元素:4

arr.unshift(0); // 在开头添加元素,返回新长度:4

arr.shift(); // 删除开头元素,返回被删除的元素:0

console.log(arr); // [1, 2, 3]

上面的提一嘴就行,说一说shiftunshift 的性能相对较差,因为它们需要移动原数组中的所有元素。

sort:排序

sort() 方法用于对数组元素进行排序,默认按字典顺序排序:

javascript 复制代码
let arr = [3, 1, 2];

console.log(arr.sort(), arr); // [1, 2, 3] [1, 2, 3],原数组被修改

// 升序排序

console.log(arr.sort((a, b) => a - b));

// 降序排序

console.log(arr.sort((a, b) => b - a));

// 默认字典排序(注意数字也会被转为字符串比较)

console.log([10, 1, 20, 3, 5].sort()); // [1, 10, 20, 3, 5]

这里主要要说的就是默认排序方式不是升序,是字典排序,以utf-16为基础判断排序

splice:删除/插入/替换

splice() 用于删除、插入或替换数组元素:

javascript 复制代码
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]

该方法会返回被删除的元素,并改变了当前数组

reverse:反转数组

reverse() 方法用于反转数组中元素的顺序:

javascript 复制代码
let arr = [1, 2, 3];

console.log(arr.reverse(), arr); // [3, 2, 1] [3, 2, 1]

fill:填充数组

fill() 方法用于将数组中的元素替换为指定值:

javascript 复制代码
let arr = [1, 2, 3, 4, 5];

console.log(arr.fill(0, 1, 3), arr); // [1, 0, 0, 4, 5] [1, 0, 0, 4, 5]

传入参数为传入元素,起始位置,最后位置,瞻前不顾后

不会修改原数组的方法

这些方法不会改变原数组,而是返回新数组或新值,属于纯函数。

forEach:遍历数组

forEach() 方法用于遍历数组,无返回值:

javascript 复制代码
const arr = [1, 2, 3];

arr.forEach(item => console.log(item)); // 1 2 3

forEach的遍历有个缺陷就是不能停,如果非要问你停下来的方法,当然也有,但是要先说,不推荐,如果该遍历需要停止的话,最好和最直接的方法就是用for...of方法来遍历,然后break停止。

javascript 复制代码
// 报错停止
try {
  [1, 2, 3, 4].forEach(num => {
    if (num === 2) throw new Error("Stop");
    console.log(num);
  });
} catch (e) {}

// 修改数组长度
let arr = [1, 2, 3, 4];
arr.forEach((num, idx, a) => {
  if (num === 2) {
    a.length = idx + 1; // 直接截断数组
  }
  console.log(num);
});

// 强制不输出
let stop = false;
[1, 2, 3, 4].forEach(num => {
  if (stop) return; // 后续全部 return,相当于不执行逻辑
  if (num === 2) {
    stop = true; // 标记后面的都 return
    return;
  }
  console.log(num);
});

// 冻结数组,无法迭代了
let arr = [1, 2, 3, 4];
arr.forEach(num => {
  console.log(num);
  if (num === 2) Object.freeze(arr); // 让数组无法再被迭代
});

map:转换数组

map() 方法用于将数组中的每个元素转换为新元素,并返回新数组:

javascript 复制代码
const arr = [1, 2, 3];

const doubled = arr.map(item => item * 2);

console.log(doubled); // [2, 4, 6]

console.log(arr); // [1, 2, 3] 原数组未改变

还有map 在 React 一个非常重要的用途,就是把一组数据映射成一组组件,从而实现数据驱动的界面展示

javascript 复制代码
function UserList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}
为什么不用 forEach?
  • forEach 没有返回值,无法直接生成一组 JSX;
  • 而map 返回新数组,正好就是一组组件,非常契合 React 的渲染机制。

查找类方法

从演变角度回答,这个看情况,一题时间拉太长了也不好

indexOf/lastIndexOf(ES5)

用于查找元素在数组中的位置:

javascript 复制代码
const arr = [1, 2, 3, 2];

console.log(arr.indexOf(2)); // 1,找到第一个匹配项的索引

console.log(arr.lastIndexOf(2)); // 3,找到最后一个匹配项的索引

find/findIndex(ES6)

用于查找满足条件的第一个元素或其索引:

javascript 复制代码
const people = [

{name: 'Alice', age: 20},

{name: 'Bob', age: 25}

];

// 查找满足条件的第一个元素

const person = people.find(p => p.age > 20);

console.log(person); // {name: 'Bob', age: 25}

// 查找满足条件的第一个元素的索引

const index = people.findIndex(p => p.age > 20);

console.log(index); // 1

includes(ES6)

用于判断数组是否包含某个元素:

javascript 复制代码
const arr = [1, 2, 3];

console.log(arr.includes(2)); // true

console.log(arr.includes(4)); // false

这个方法比较好用和常用在实际中,提一嘴。

过滤和判定类方法

filter:过滤数组

filter() 方法用于过滤出满足条件的元素,返回新数组:

javascript 复制代码
const arr = [1, 2, 3, 4, 5];

const evens = arr.filter(item => item % 2 === 0);

console.log(evens); // [2, 4]

这个是有手写题的,没写过容易被拷打一遍。

javascript 复制代码
Array.prototype.myFilter = function(callback, thisArg) {
  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }
  const result = [];
  const arr = this;
  for (let i = 0; i < arr.length; i++) {
    if (i in arr) {
      if (callback.call(thisArg, arr[i], i, arr)) {
        result.push(arr[i]);
      }
    }
  }
  return result;
};

every/some:判定数组

every()some() 方法用于判断数组元素是否都满足或至少有一个满足某个条件:

javascript 复制代码
const people = [

{name: 'Alice', age: 20, role: "user"},

{name: 'Bob', age: 25, role: "admin"},

{name: 'Charlie', age: 30, role: "user"}

];

// 检查是否所有人都成年

const allAdults = people.every(person => person.age >= 18);

console.log(allAdults); // true

// 检查是否有管理员

const hasAdmin = people.some(person => person.role === "admin");

console.log(hasAdmin); // true

拼接/裁剪类方法

slice:截取数组

slice() 方法用于截取数组的一部分,返回新数组:

javascript 复制代码
const arr = [1, 2, 3, 4, 5];

const subArr = arr.slice(1, 3);

console.log(subArr); // [2, 3]

console.log(arr); // [1, 2, 3, 4, 5] 原数组未改变

concat:合并数组

concat() 方法用于合并数组:

javascript 复制代码
const arr1 = [1, 2];

const arr2 = [3, 4];

const newArr = arr1.concat(arr2);

console.log(newArr); // [1, 2, 3, 4]

如果需要移除元素但不修改原数组,可以使用 slice 和 concat:

javascript 复制代码
const arr = [1, 2, 3, 4, 5];

// 移除索引2开始的2个元素,但不修改原数组

const newArr = arr.slice(0, 2).concat(arr.slice(4));

console.log('新数组:', newArr); // [1, 2, 5]

console.log('原数组:', arr); // [1, 2, 3, 4, 5]

扁平化方法

flat/flatMap(ES2019)

用于将多维数组扁平化:

javascript 复制代码
const arr = [1, [2, 3, [4, 5]]];

console.log(arr.flat()); // [1, 2, 3, [4, 5]] 默认只展开一层

console.log(arr.flat(2)); // [1, 2, 3, 4, 5] 指定展开2层

// flatMap = map + flat

const arr2 = [1, 2, 3];

console.log(arr2.flatMap(x => [x, x * 2])); // [1, 2, 2, 4, 3, 6]

之前看面筋有一题就和这个相关,将[1, [2, 3, [4, [5,6,[7,8,9]]]]],变成[1,2,3,4,5,6,7,8,9]

javascript 复制代码
// flat 方法
const arr = [1, [2, 3, [4, [5,6,[7,8,9]]]]];
const res = arr.flat(Infinity);
console.log(res); 
// [1,2,3,4,5,6,7,8,9]

// JSON.stringify 方法,有思路,但我正则写不来,不会的还是慎用
const arr = [1, [2, 3, [4, [5,6,[7,8,9]]]]];
const res = JSON.stringify(arr).replace(/\[|\]/g, '').split(',').map(Number);
console.log(res);
// [1,2,3,4,5,6,7,8,9]

迭代器方法

keys/values/entries

这些方法返回数组的迭代器:

javascript 复制代码
const arr = [3, 3, 3];

// values迭代器(默认)

for(let item of arr) {

console.log(item); // 3 3 3

}

// entries迭代器,同时获取索引和值

for(let [index, item] of arr.entries()) {

console.log(index, item); // 0 3, 1 3, 2 3

}

对象不能直接用 for...of ?(因为普通对象没有实现迭代器协议),可以用keys方法判断数据内容。

join/toString:转换为字符串

javascript 复制代码
const arr = [1, 2, 3];

console.log(arr.join('-')); // "1-2-3"

console.log(arr.toString()); // "1,2,3"

静态方法

Array.isArray:判断是否为数组

javascript 复制代码
console.log(Array.isArray([])); // true

console.log(Array.isArray({})); // false

有了它就不用Object.prototype.toString.call()去判断是不是数组了,之前手写一个场景题用这个被阴阳了。

Array.from:从类数组对象创建数组

javascript 复制代码
// 从字符串创建数组

console.log(Array.from('hello')); // ['h', 'e', 'l', 'l', 'o']

// 从Set创建数组

console.log(Array.from(new Set([1, 2, 2, 3]))); // [1, 2, 3]

// 从NodeList创建数组

console.log(Array.from(document.querySelectorAll('div')));

// 第二个参数可以指定映射函数

console.log(Array.from([1, 2, 3], x => x * 2)); // [2, 4, 6]

// 创建26个字母的数组

console.log(Array.from(new Array(26), (val, index) => String.fromCodePoint(index + 65)));

它也可以实现类似map的功能,但是将数组创建为数组就很别扭,人家主流功能还是将类数组对象创建为数组。

Array.of:创建数组

javascript 复制代码
console.log(Array.of(1, 2, 3)); // [1, 2, 3]

// 与new Array的区别

console.log(new Array(3)); // [empty × 3]

console.log(Array.of(3)); // [3]

总结

JavaScript 数组方法丰富多样,根据是否修改原数组可分为两类:

  1. 会修改原数组的方法:push/pop/shift/unshift、sort、splice、reverse、fill 等

  2. 不会修改原数组的方法:map、filter、slice、concat、reduce 等纯函数

从优化角度回答,当然也不要为了性能优化而性能优化,把东西做出来再考虑。

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了4 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅4 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端