前端面试之——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 等纯函数

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

相关推荐
skeletron201110 分钟前
【基础】React工程配置(基于Vite配置)
前端
怪可爱的地球人11 分钟前
前端
蓝胖子的小叮当19 分钟前
JavaScript基础(十四)字符串方法总结
前端·javascript
跟橙姐学代码1 小时前
Python 函数实战手册:学会这招,代码能省一半!
前端·python·ipython
森之鸟1 小时前
审核问题——鸿蒙审核返回安装失败,可以尝试云调试
服务器·前端·数据库
jiayi1 小时前
从 0 到 1 带你打造一个工业级 TypeScript 状态机
前端·设计模式·状态机
轻语呢喃1 小时前
CSS水平垂直居中的9种方法:原理、优缺点与差异对比
前端·css
!win !1 小时前
uni-app支付宝端彻底禁掉下拉刷新效果
前端·小程序·uni-app
xw51 小时前
uni-app支付宝端彻底禁掉下拉刷新效果
前端·支付宝
@大迁世界2 小时前
这次 CSS 更新彻底改变了我的 CSS 开发方式。
前端·css