JavaScript数组与字符串方法深度解析

563 阅读8分钟

JavaScript数组与字符串方法深度解析

前言

在前端面试中,数组和字符串方法的考察频率极高,面试官不仅会考察你是否知道这些方法,更会关注你对方法细节的理解、应用场景的选择以及性能差异的认知。本文将深入剖析JavaScript中数组和字符串的各种方法,,详细讲解每个方法的参数、返回值、使用场景以及相似方法之间的区别,帮助你全面提升面试表现。

正文

1. JavaScript数组方法深度解析

1.1 增加元素的方法

push()

  • 参数:一个或多个要添加的元素
  • 返回值:数组的新长度
  • 特点:直接修改原数组
  • 面试题:
    • pushconcat的区别是什么?(push修改原数组,concat返回新数组)
    • push可以一次添加多个元素吗?(可以)
let arr = [1, 2];
let length = arr.push(3, 4); // arr变为[1,2,3,4],length为4

unshift()

  • 参数:一个或多个要添加的元素
  • 返回值:数组的新长度
  • 特点:在数组开头添加,性能比push差(需要移动所有元素)
  • 面试题:
    • 大量数据插入时,unshiftpush哪个性能更好?(push更好)
    • unshift能添加多个元素吗?(可以)
let arr = [3, 4];
let length = arr.unshift(1, 2); // arr变为[1,2,3,4],length为4

splice()

  • 参数:
    • 第一个参数:开始修改的位置(负数表示倒数)
    • 第二个参数:要删除的元素个数(0表示不删除)
    • 后续参数:要添加的元素
  • 返回值:由被删除元素组成的数组
  • 特点:功能强大,可实现增删改
  • 面试题:
    • 如何用splice实现数组去重?
    • spliceslice的区别是什么?(splice修改原数组,slice不修改)
let arr = [1, 2, 5, 6];
let deleted = arr.splice(2, 0, 3, 4); // arr变为[1,2,3,4,5,6],deleted为[]

concat()

  • 参数:数组或值
  • 返回值:新数组
  • 特点:不修改原数组,浅拷贝
  • 面试题:
    • concat能合并多个数组吗?(可以)
    • concat会深拷贝对象吗?(不会,是浅拷贝)
let arr1 = [1], arr2 = [2];
let newArr = arr1.concat(arr2, 3, [4,5]); // [1,2,3,4,5]
1.2 删除元素的方法

pop()

  • 参数:无
  • 返回值:被删除的元素
  • 特点:修改原数组,空数组返回undefined
  • 面试题:
    • 如何用pop实现栈结构?
    • popshift的性能差异?(pop更好)
let arr = [1, 2, 3];
let last = arr.pop(); // arr变为[1,2],last为3

shift()

  • 参数:无
  • 返回值:被删除的元素
  • 特点:修改原数组,性能较差(需要移动所有元素)
  • 面试题:
    • 如何用shift实现队列结构?
    • 为什么shiftpop慢?(需要移动所有元素)
let arr = [1, 2, 3];
let first = arr.shift(); // arr变为[2,3],first为1

splice()删除用法

  • 面试题:
    • 如何删除数组最后一个元素?(arr.splice(-1,1)
    • 如何删除数组中间元素?
let arr = [1, 2, 3, 4];
let deleted = arr.splice(1, 2); // arr变为[1,4],deleted为[2,3]

slice()

  • 参数:
    • 第一个参数:起始索引(包含)
    • 第二个参数:结束索引(不包含)
  • 返回值:新数组
  • 特点:不修改原数组,负数索引表示倒数
  • 面试题:
    • 如何复制一个数组?(arr.slice()arr.slice(0)
    • slicesplice的区别?
let arr = [1, 2, 3, 4];
let newArr = arr.slice(1, 3); // [2,3],arr不变
1.3 修改数组的方法

reverse()

  • 参数:无
  • 返回值:反转后的数组
  • 特点:直接修改原数组
  • 面试题:
    • reverse会改变原数组吗?(会)
    • 如何不修改原数组实现反转?([...arr].reverse()
let arr = [1, 2, 3];
arr.reverse(); // arr变为[3,2,1]

sort()

  • 参数:比较函数(可选)
  • 返回值:排序后的数组
  • 特点:直接修改原数组,默认按字符串Unicode排序
  • 面试题:
    • 如何实现数字数组的正确排序?
    • sort的时间复杂度是多少?(V8引擎使用快速排序和插入排序,O(n log n))
let arr = [10, 5, 20];
arr.sort(); // [10,20,5](按字符串排序)
arr.sort((a,b) => a-b); // [5,10,20](数字升序)
1.4 查找元素的方法

indexOf() vs lastIndexOf()

  • 共同参数:要查找的元素,起始位置(可选)
  • 区别:
    • indexOf从前往后找
    • lastIndexOf从后往前找
  • 面试题:
    • 如何判断元素是否存在?(indexOf !== -1includes
    • 两者性能有区别吗?(大数据量下indexOf可能更快)
let arr = [1, 2, 3, 2];
arr.indexOf(2); // 1
arr.lastIndexOf(2); // 3

includes()

  • 参数:要查找的值,起始位置(可选)
  • 返回值:布尔值
  • 特点:可以识别NaN(indexOf不能)
  • 面试题:
    • includes能查找NaN吗?(可以)
    • includesindexOf如何选择?(只需要布尔值时用includes
let arr = [1, 2, NaN];
arr.includes(NaN); // true
arr.indexOf(NaN); // -1

find()

  • 参数:回调函数
  • 返回值:第一个满足条件的元素,没有则返回undefined
  • 特点:可以查找复杂对象
  • 面试题:
    • findfilter的区别?(find返回第一个元素,filter返回所有)
    • 如何用find查找对象数组?
let users = [{id:1,name:'A'}, {id:2,name:'B'}];
users.find(u => u.id === 2); // {id:2,name:'B'}
1.5 遍历数组的方法

forEach() vs map()

  • 共同点:都遍历数组
  • 区别:
    • map返回新数组,forEach不返回
    • map适合需要返回值的场景,forEach适合只执行操作的场景
  • 面试题:
    • 什么情况下用map而不是forEach?(需要新数组时)
    • 如何提前终止forEach?(无法直接终止,可用some/every代替)
let arr = [1, 2, 3];
arr.forEach(x => console.log(x)); // 无返回值
let doubled = arr.map(x => x * 2); // [2,4,6]

filter()

  • 参数:回调函数
  • 返回值:新数组
  • 特点:不修改原数组
  • 面试题:
    • filterfind的区别?(filter返回所有匹配,find返回第一个)
    • 如何用filter去重?
let arr = [1, 2, 3, 2];
let unique = arr.filter((x,i) => arr.indexOf(x) === i); // [1,2,3]

reduce()

  • 参数:
    • 回调函数(accumulator, currentValue, index, array)
    • 初始值(可选)
  • 返回值:累加结果
  • 面试题:
    • 如何用reduce实现map功能?
    • reduce的初始值不传会怎样?(使用数组第一个元素作为初始值)
let arr = [1, 2, 3];
let sum = arr.reduce((acc, cur) => acc + cur, 0); // 6
let mapResult = arr.reduce((acc, cur) => [...acc, cur*2], []); // [2,4,6]
1.6 数组转换方法

join()

  • 参数:分隔符(默认逗号)
  • 返回值:字符串
  • 面试题:
    • 如何将数组转为以竖线分隔的字符串?(arr.join('|')
    • jointoString的区别?(toString固定使用逗号分隔)
let arr = [1, 2, 3];
arr.join(); // "1,2,3"
arr.join(''); // "123"

2. JavaScript字符串方法深度解析

2.1 增加内容的方法

concat()

  • 参数:多个字符串
  • 返回值:新字符串
  • 特点:不修改原字符串,性能不如+操作符
  • 面试题:
    • 为什么推荐使用+而不是concat?(+性能更好)
    • concat能连接多个字符串吗?(可以)
let str = 'Hello';
str.concat(' ', 'World'); // "Hello World"

padStart() vs padEnd()

  • 共同参数:
    • 目标长度
    • 填充字符串(默认空格)
  • 区别:
    • padStart在前面填充
    • padEnd在后面填充
  • 面试题:
    • 如何用padStart实现数字前补零?
    • 填充字符串会截断吗?(会,确保总长度不超过目标长度)
'5'.padStart(2, '0'); // "05"
'1'.padEnd(3, '0'); // "100"
2.2 删除内容的方法

slice() vs substring() vs substr()

  • 共同点:都提取子字符串
  • 区别:
    • slice:参数(start,end),接受负数
    • substring:参数(start,end),负数视为0,自动交换参数
    • substr:参数(start,length),第一个参数接受负数
  • 面试题:
    • 三个方法的参数区别?
    • 哪个方法被标记为废弃?(substr
let str = 'Hello';
str.slice(1,3); // "el"
str.substring(1,3); // "el"
str.substr(1,3); // "ell"
2.3 修改字符串的方法

replace()

  • 参数:
    • 查找值(字符串或正则)
    • 替换值(字符串或函数)
  • 返回值:新字符串
  • 面试题:
    • 如何替换所有匹配项?(使用正则加g标志)
    • 替换函数参数有哪些?
'Hello World'.replace('World', 'JS'); // "Hello JS"
'abab'.replace(/a/g, 'c'); // "cbcb"

trim()系列

  • 方法:
    • trim():去除两端空白
    • trimStart()/trimLeft():去除开头空白
    • trimEnd()/trimRight():去除结尾空白
  • 面试题:
    • trimLefttrimStart的区别?(别名,功能相同)
    • 如何自定义去除字符?(可用replace
' Hello '.trim(); // "Hello"
' Hello '.trimStart(); // "Hello "
2.4 查找内容的方法

includes() vs indexOf()

  • 共同点:都可查找子串
  • 区别:
    • includes返回布尔值
    • indexOf返回位置
  • 面试题:
    • 什么时候用includes?(只需要知道是否存在时)
    • 哪个方法性能更好?(简单场景差异不大)
'Hello'.includes('ell'); // true
'Hello'.indexOf('ell'); // 1

startsWith() vs endsWith()

  • 参数:
    • 要查找的字符串
    • 起始位置(可选)
  • 面试题:
    • 如何检查文件扩展名?(endsWith
    • 如何检查URL协议?(startsWith
'file.txt'.endsWith('.txt'); // true
'https://...'.startsWith('https'); // true
2.5 转换方法

split()

  • 参数:
    • 分隔符(字符串或正则)
    • 限制数量(可选)
  • 返回值:数组
  • 面试题:
    • 如何将字符串转为字符数组?(str.split('')
    • 如何实现多分隔符分割?(使用正则)
'a,b,c'.split(','); // ["a","b","c"]
'a,b.c'.split(/[,.]/); // ["a","b","c"]

charCodeAt()

  • 参数:索引
  • 返回值:Unicode编码
  • 相关方法:
    • String.fromCharCode():编码转字符
  • 面试题:
    • 如何获取字符的ASCII码?(charCodeAt
    • 如何判断字符是大写字母?(charCodeAt(0) >= 65 && <= 90
'A'.charCodeAt(0); // 65
String.fromCharCode(65); // "A"

结语

本文从面试角度深入解析了JavaScript数组和字符串的各种方法,涵盖了参数说明、返回值、使用场景、性能考量以及相似方法之间的区别等关键知识点。在面试中,面试官不仅会考察你是否知道这些方法,更会关注:

  1. 方法的选择依据(为什么用A方法而不用B方法)
  2. 对方法细节的掌握(参数处理、边界情况)
  3. 性能方面的考量(大数据量下的表现)
  4. 实际应用能力(如何组合使用这些方法解决问题)

建议读者在学习时:

  • 多动手实践每个方法的示例代码
  • 思考相似方法之间的区别和应用场景
  • 关注方法的性能特点
  • 尝试用这些方法解决实际问题

掌握这些基础方法不仅能帮助你在面试中脱颖而出,更能提升日常开发效率和代码质量。祝你在前端之路上越走越远!🚀