春招面试拷打实录(二):揭秘高频难题与应对策略🧐

564 阅读23分钟

引言

春招来袭,面对面试中的难题,不少人都感到头疼。本文将分享一些常见的面试问题及应对策略,希望能帮助你在准备过程中更加得心应手,顺利通过面试。让我们一起加油,向着理想offer冲刺吧!🚀

vue3 生命周期

Vue 3 的生命周期钩子函数与 Vue 2 类似,但有一些细微的变化和新增的组合式 API(Composition API)钩子。以下是 Vue 3 的生命周期钩子及其执行顺序:

1. beforeCreate

  • 触发时机:在实例初始化之后,数据观测 (data observer) 和事件/侦听器配置之前被调用。
  • 用途:此时组件的 data 和 methods 还未初始化,通常用于执行一些初始化操作。

2. created

  • 触发时机:在实例创建完成后被立即调用。此时,数据观测 (data observer)、属性和方法的运算、watch/event 事件回调已经设置完成。
  • 用途:可以访问 data 和 methods,但 DOM 还未生成,通常用于发起异步请求。

3. beforeMount

  • 触发时机:在挂载开始之前被调用,相关的 render 函数首次被调用。
  • 用途:此时模板已经编译完成,但尚未将模板渲染到 DOM 中。

4. mounted

  • 触发时机:在实例挂载到 DOM 后被调用。此时,组件已经出现在页面中,DOM 已经生成。
  • 用途:可以访问 DOM 元素,通常用于操作 DOM 或发起依赖于 DOM 的请求。

5. beforeUpdate

  • 触发时机:在数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。
  • 用途:可以在更新之前访问现有的 DOM,例如手动移除事件监听器。

6. updated

  • 触发时机:在数据更改导致的虚拟 DOM 重新渲染和打补丁之后调用。
  • 用途:可以执行依赖于 DOM 更新的操作,但要注意避免无限循环的更新。

7. beforeUnmount (Vue 2 中的 beforeDestroy)

  • 触发时机:在实例卸载之前调用。
  • 用途:此时实例仍然完全可用,通常用于清理工作,如取消定时器、移除事件监听器等。

8. unmounted (Vue 2 中的 destroyed)

  • 触发时机:在实例卸载之后调用。
  • 用途:此时所有的指令和事件监听器都已被移除,子实例也都被销毁。

9. errorCaptured

  • 触发时机:当捕获一个来自子孙组件的错误时被调用。
  • 用途:可以用于处理组件树中的错误,返回 false 可以阻止错误继续向上传播。

10. renderTracked (开发模式)

  • 触发时机:在渲染过程中跟踪到响应式依赖时调用。
  • 用途:用于调试,了解哪些依赖被跟踪。

11. renderTriggered (开发模式)

  • 触发时机:在响应式依赖触发重新渲染时调用。
  • 用途:用于调试,了解哪些依赖触发了重新渲染。

生命周期图示

beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeUnmount -> unmounted

总结

Vue 3 的生命周期钩子函数与 Vue 2 类似,但在组合式 API (setup 函数) 中,生命周期钩子是通过 onXXX 函数来使用的。

ref 与 reactive 的区别

ref 和 reactive 都是用来创建响应式数据的方法,但它们的使用场景和工作方式有所不同。

ref

  • 用途:ref 主要用于创建一个包含值的响应式引用对象。它可以用来包裹基本类型(如字符串、数字等)或对象类型的数据。
  • 访问与修改:由于 ref 创建的是一个对象,因此在模板中可以直接使用,但在 JS 代码中访问其值时需要通过 .value 属性来获取或设置值。
  • 解构:当你解构 ref 或者将它传递给函数参数时,你得到的是它的原始值而非响应式的引用。如果需要保持响应性,可以考虑使用 toRefs 方法。

reactive

  • 用途:reactive 是用来创建一个响应式的对象。它使得对象的所有嵌套层次都具有响应性,非常适合用于处理复杂状态管理。
  • 访问与修改:直接通过属性名进行访问和修改即可,不需要像 ref 那样使用 .value。
  • 限制:只能对对象(包括数组和普通 JavaScript 对象)进行代理,不能直接作用于基本数据类型。

总结

  • 使用 ref 可以更灵活地处理基本类型数据,并且在某些情况下(比如在组合式 API 函数之间共享状态)可能更加方便。
  • reactive 则提供了一种更为直观的方式来处理对象类型的响应式状态,特别是对于那些拥有多个相关联状态属性的情况。

vue3 组件

在 Vue 3 中,为了提升用户体验和优化应用性能,引入了几个关键组件和特性。以下是这些特性的优化介绍:

  • Transition: <Transition> 组件用于包裹元素或组件,为它们的进入和离开添加动画效果。Vue 自动检测元素或组件的添加或移除,并应用相应的过渡类名,允许通过 CSS 或 JavaScript 钩子自定义进入和离开时的动画。

  • TransitionGroup: 类似于 <Transition>,但 <TransitionGroup> 适用于一组需要过渡效果的元素或组件。它不仅处理单个元素的进入和离开,还处理列表中元素的变化,如添加、删除或重新排序。使用 <TransitionGroup> 包裹的元素必须拥有唯一的 key 属性。

  • KeepAlive: 抽象组件 <KeepAlive> 缓存动态组件或路由视图,避免切换时销毁和重建组件,有助于维持组件状态,提高用户体验。可通过 include 和 exclude 属性指定哪些组件应被缓存。

  • Teleport: <Teleport>(之前版本称为 Portal)允许将子组件渲染至 DOM 中的不同位置。不同于常规组件渲染于父组件的内容分发处,<Teleport> 可指定一个目标元素作为挂载点,即使该位置位于组件层次结构之外,也能将内容挂载于此。

  • Suspense: 新增的实验性特性 <Suspense>,在等待异步依赖(例如异步组件)加载完成前显示备用内容。当组件树的一部分正在等待异步操作完成时,<Suspense> 能展示加载状态或其他占位符内容,直至所有数据准备就绪。

vue-router 中的 router和route

在 Vue.js 中,vue-router 是用于实现单页面应用(SPA)路由管理的官方库,router 和 route 是 vue-router 中两个非常重要的概念,它们分别代表不同的对象和用途。

 1.router 是什么?

router 是 vue-router 的核心实例,负责管理整个应用的路由。你可以把它想象成一个“路由器”,它决定了当你点击一个链接或者改变浏览器地址时,应用应该加载哪个组件。

router 的主要职责:

  • 路由配置:你需要在 router 中定义路由规则,比如 /home 对应 Home 组件,/about 对应 About 组件。
  • 导航控制:router 提供了导航方法,比如 push、replace、go 等,用于在代码中跳转到不同的路由。
  • 全局钩子:router 还支持全局的路由守卫(如 beforeEach、afterEach),可以在路由跳转前后执行一些逻辑,比如权限校验、页面加载动画等。

router 的常见用法:

  • 在项目中,你会先创建一个 router 实例,并配置路由规则。
  • 然后将这个 router 实例挂载到 Vue 的根实例中,这样整个应用就具备了路由功能。
  • 在组件中,你可以通过 this.$router 访问 router 实例,调用它的方法进行导航。

 2.route 是什么?

route 是当前激活的路由对象,它包含了当前路由的详细信息。你可以把它理解为一个“快照”,记录了当前路由的状态。

route 的主要职责:

  • 提供路由信息:route 包含了当前路由的路径(path)、参数(params)、查询字符串(query)、哈希值(hash)等信息。
  • 动态路由匹配:如果你的路由是动态的(比如 /user/:id),route 会解析出动态参数(如 id),方便你在组件中使用。
  • 嵌套路由信息:route 还包含了嵌套路由的匹配记录(matched),方便你处理复杂的路由结构。

route 的常见用法:

  • 在组件中,你可以通过 this.$route 访问当前的路由对象。
  • 比如,你可以通过 this.$route.params.id 获取动态路由参数,或者通过 this.$route.query.search 获取查询字符串。

3. router 和 route 的关系

  • router 是管理者,route 是被管理者:router 负责管理路由的跳转和全局配置,而 route 是 router 跳转后的结果,记录了当前路由的状态。
  • router 改变 route:当你调用 router.push 或 router.replace 时,router 会根据配置的路由规则,找到匹配的组件,并更新 route 对象。
  • route 是只读的:route 对象是只读的,你不能直接修改它。如果你想改变路由,必须通过 router 的方法(如 push、replace)来实现。

4. 总结

  • router 是路由的管理者,负责路由的跳转、配置和全局守卫。
  • route 是当前路由的状态对象,提供了当前路由的详细信息。
  • 它们的关系是:router 控制路由的跳转,跳转后生成新的 route 对象,route 则记录了当前路由的状态。

js 的基本数据类型和引用数据类型

在 JavaScript 中,数据类型可以分为两大类:基本数据类型(原始类型) 和 引用数据类型(对象类型) 。它们的核心区别在于 存储方式 和 操作方式。

1. 基本数据类型(Primitive Types)

基本数据类型是 JavaScript 中最基础的数据类型,它们的值直接存储在变量中,占用固定的内存空间。基本数据类型是不可变的(immutable),也就是说,一旦创建,它们的值就不能被修改。

JavaScript 中的基本数据类型有以下 7 种: number、string、boolean、null、undefined、symbol、bigint。

2. 引用数据类型(Reference Types)

引用数据类型是复杂的数据类型,它们的值存储在堆内存中,变量中存储的是指向堆内存中对象的引用(地址)。引用数据类型是可变的(mutable),也就是说,它们的值可以被修改。

JavaScript 中的引用数据类型主要包括: object、array、function 等。

3. 基本数据类型 vs 引用数据类型

特性基本数据类型引用数据类型
存储方式值直接存储在栈内存中值存储在堆内存中,变量存储的是引用(地址)
可变性不可变(immutable)可变(mutable)
比较方式比较的是值比较的是引用(地址)
复制行为复制的是值复制的是引用
内存占用占用固定大小的内存占用不固定的内存,动态分配
示例let a = 10;let obj = { name: "Alice" };

4. 注意事项

  • 浅拷贝和深拷贝:
    对于引用数据类型,直接赋值只是复制了引用,如果需要复制值,需要使用浅拷贝或深拷贝。

    • 浅拷贝:Object.assign() 或扩展运算符 ...。
    • 深拷贝:JSON.parse(JSON.stringify(obj)) 或使用工具库(如 Lodash)。
  • 类型检测:
    使用 typeof 可以检测基本数据类型,但对于引用数据类型(如 null、array),typeof 的结果可能不准确。可以使用 instanceof 或 Object.prototype.toString.call() 进行更准确的检测。

5. 总结

  • 基本数据类型:number、string、boolean、null、undefined、symbol、bigint。
  • 引用数据类型:object、array、function 等。
  • 核心区别:基本数据类型存储的是值,引用数据类型存储的是引用。

ts 的基本数据类型

TypeScript 是 JavaScript 的超集,它在 JavaScript 的基础上增加了静态类型系统。TypeScript 的基本数据类型几乎包含了 JavaScript 的所有基本数据类型,并在此基础上增加了一些额外的类型。以下是 TypeScript 中的基本数据类型:

  • JavaScript 的原始类型:number、string、boolean、null、undefined、symbol、bigint。
  • TypeScript 特有的类型:
    • void:表示没有任何返回值的类型,通常用于函数返回值。
    • any:表示任意类型,关闭类型检查。
    • unknown:表示未知类型,比 any 更安全,需要进行类型检查后才能使用。
    • never:表示永远不会发生的类型,通常用于抛出异常或无限循环的函数。
    • object:表示非原始类型的对象类型。
    • array:表示数组类型,可以用两种方式定义:使用 类型[] 语法;使用泛型 Array<类型> 语法。
    • tuple:表示元组类型,用于表示固定长度和类型的数组。
    • enum:表示枚举类型,用于定义一组命名的常量。
  • 其他高级类型:
    • 联合类型('|'):表示一个值可以是多种类型之一。
    • 交叉类型('&'):表示一个值必须同时满足多种类型。
    • 字面量类型、类型别名、函数类型

 TypeScript 类型 vs JavaScript 类型

  • TypeScript 的类型是静态的,在编译时进行类型检查。
  • JavaScript 的类型是动态的,在运行时确定。
  • TypeScript 的类型系统增强了代码的可读性和可维护性,同时减少了运行时错误。

ts 的泛型和接口

1. 泛型(Generics)

泛型是一种创建可重用组件的方式,它允许我们在定义函数、类或接口时使用类型参数,而不是直接指定具体类型。泛型的核心思想是 参数化类型。

2. 接口(Interfaces)

接口是 TypeScript 中用于定义对象结构的工具。它描述了对象的属性、方法以及它们的类型。接口的核心思想是 定义契约,确保对象符合特定的结构。

tcp 与 udp 的区别

特性TCPUDP
全称Transmission Control ProtocolUser Datagram Protocol
连接方式面向连接(通过三次握手建立连接)无连接
可靠性可靠传输(确认、重传、流量控制)不可靠传输
数据传输方式面向字节流面向报文
性能开销大,传输效率较低开销小,传输效率较高
头部大小较大(通常 20 字节)较小(固定 8 字节)
顺序保证数据按序到达数据可能乱序到达
流量控制支持(滑动窗口机制)不支持
拥塞控制支持(慢启动、拥塞避免等)不支持
适用场景文件传输、网页浏览、电子邮件视频流、在线游戏、语音通话

总结

  • TCP:适合对可靠性要求高的场景,如文件传输、网页浏览等。
  • UDP:适合对实时性要求高的场景,如视频流、在线游戏等。

udp 如何实现稳定传输

UDP(User Datagram Protocol)本身是一个无连接、不可靠的传输协议,它不提供数据包的确认、重传、排序和拥塞控制等机制。然而,在某些应用场景中,我们可能需要在 UDP 的基础上实现一定程度的稳定传输。以下是几种常见的实现方式:

- 应用层实现确认和重传机制 在应用层模拟 TCP 的确认(ACK)和重传机制,确保数据包的可靠传输。

- 实现数据包排序 UDP 不保证数据包的顺序,因此需要在应用层实现数据包的排序。

- 实现流量控制 UDP 本身没有流量控制机制,但可以通过应用层实现简单的流量控制。

- 实现拥塞控制 UDP 本身没有拥塞控制机制,但可以通过应用层实现简单的拥塞控制。

- 使用可靠传输协议(如 RUDP、QUIC) 如果应用场景对可靠性要求较高,可以直接使用基于 UDP 的可靠传输协议,如 RUDP(Reliable UDP)或 QUIC(Quick UDP Internet Connections)。

- 结合前向纠错(FEC) 前向纠错(Forward Error Correction,FEC)是一种通过添加冗余数据来纠正传输错误的技术。

介绍 vuex和pinia 的核心结构

1. Vuex 的核心结构

Vuex 是 Vue.js 官方推荐的状态管理库,采用集中式存储管理应用的所有组件的状态。它的核心结构包括以下几个部分:

  • State

    • 作用:存储应用的状态数据,类似于组件的 data。
    • 特点:状态是响应式的,状态变化会自动更新视图。
  • Getters

    • 作用:从 state 中派生出一些状态,类似于组件的 computed。
    • 特点:可以对 state 进行计算或过滤,避免重复代码。
  • Mutations

    • 作用:用于同步修改 state 的唯一方式。
    • 特点:必须是同步函数,通过 commit 方法调用。
  • Actions

    • 作用:用于处理异步操作,提交 mutation 来修改 state。
    • 特点:可以包含任意异步操作,通过 dispatch 方法调用。
  • Modules

    • 作用:将 store 分割成模块,每个模块拥有自己的 state、getters、mutations 和 actions。
    • 特点:适合大型应用,避免 store 过于臃肿。

2. Pinia 的核心结构

Pinia 是 Vue.js 的下一代状态管理库,相比于 Vuex,它更轻量、更简单,同时保留了 Vuex 的核心功能。Pinia 的核心结构包括以下几个部分:

  • (1)State

    • 作用:存储应用的状态数据,类似于 Vuex 的 state。
    • 特点:状态是响应式的,可以直接修改。
  • (2)Getters

    • 作用:从 state 中派生出一些状态,类似于 Vuex 的 getters。
    • 特点:支持缓存,计算结果会被缓存直到依赖的状态发生变化。
  • (3)Actions

    • 作用:用于修改 state,可以包含同步或异步操作。
    • 特点:没有 mutations,直接通过 actions 修改 state。

3. Vuex 和 Pinia 的对比

特性VuexPinia
核心结构State、Getters、Mutations、ActionsState、Getters、Actions
异步操作通过 Actions 处理直接通过 Actions 处理
模块化通过 Modules 实现每个 Store 独立,天然模块化
TypeScript 支持需要额外配置原生支持 TypeScript
API 设计较复杂,学习成本较高更简单直观,学习成本低
体积较大更轻量
适用场景大型复杂应用中小型应用或需要轻量状态管理的场景

如果vuex 刷新后数据消失了怎么办

  •  手动持久化状态: 通过手动将状态保存到 localStorage 或 sessionStorage,并在页面加载时恢复状态。

  •  使用插件自动持久化状态: 可以使用第三方插件(如 vuex-persistedstate)来自动实现状态的持久化。 vuex-persist 是另一个流行的 Vuex 持久化插件,支持更灵活的配置。

  •  结合 Cookie 持久化状态: 如果需要将状态持久化到 Cookie 中,可以使用 js-cookie 库。

node.js 处理多个异步

1. 回调函数(Callback)

回调函数是 Node.js 中最基础的异步处理方式,但容易导致“回调地狱”(Callback Hell)。

缺点:

  • 嵌套层级深,代码难以维护。
  • 错误处理复杂。

2. Promise

Promise 是 ES6 引入的异步编程解决方案,可以避免回调地狱。

优点:

  • 链式调用,代码更清晰。
  • 支持统一的错误处理。

3. Async/Await

async/await 是 ES7 引入的语法糖,基于 Promise,使异步代码看起来像同步代码。

优点:

  • 代码更简洁,易读性高。
  • 错误处理更直观。

4. 并行处理多个异步操作

如果需要并行处理多个异步操作,可以使用以下方法:

(1)Promise.all

Promise.all 可以并行执行多个 Promise,并在所有 Promise 完成后返回结果。

特点:

  • 如果其中一个 Promise 失败,整个 Promise.all 会立即失败。

(2)Promise.allSettled

Promise.allSettled 会等待所有 Promise 完成,无论成功或失败。

特点:

  • 不会因为某个 Promise 失败而中断。

(3)Promise.race

Promise.race 返回最先完成的 Promise 的结果(无论成功或失败)。

特点:

  • 适合超时控制或竞速场景。

5. 事件驱动(EventEmitter)

Node.js 的 EventEmitter 可以用于处理异步事件。

6. 第三方库

可以使用第三方库(如 async)来简化异步操作。

请求拦截器 响应拦截器 干了什么

在前端开发中,请求拦截器和响应拦截器是用于在发送请求和接收响应时进行统一处理的机制。它们通常用于封装 HTTP 请求库(如 axios 或 fetch),以便在请求发出前或响应返回后执行一些通用的逻辑。

1. 请求拦截器(Request Interceptor)

请求拦截器用于在请求发出之前对请求进行统一处理。常见的用途包括:

  • 添加请求头(如 Authorization 令牌)。
  • 修改请求数据(如格式化参数)。
  • 显示加载状态(如显示 Loading 动画)。
  • 取消请求(如根据条件中断请求)。

常见场景:

  1. 添加认证信息:

    config.headers['Authorization'] = 'Bearer token';
    
  2. 格式化请求数据:

    if (config.data) {
      config.data = JSON.stringify(config.data);
    }
    
  3. 取消请求:

    if (shouldCancelRequest(config)) {
      return Promise.reject({ message: '请求被取消' });
    }
    

2. 响应拦截器(Response Interceptor)

响应拦截器用于在接收到响应之后对响应进行统一处理。常见的用途包括:

  • 统一处理错误(如 HTTP 状态码非 200 的情况)。
  • 格式化响应数据(如提取 data 字段)。
  • 隐藏加载状态(如隐藏 Loading 动画)。
  • 缓存响应数据。

常见场景:

  1. 统一处理错误:

    if (error.response.status === 401) {
      redirectToLogin();
    }
    
  2. 格式化响应数据:

    return response.data;
    
  3. 缓存响应数据:

    if (shouldCache(response)) {
      cache.set(response.config.url, response.data);
    }
    

3. 请求拦截器和响应拦截器的工作流程

以下是请求拦截器和响应拦截器的工作流程:

  1. 请求发出前:

    • 请求拦截器对请求配置进行处理。
    • 如果请求拦截器返回 config,请求会继续发出。
    • 如果请求拦截器返回 Promise.reject,请求会被中断。
  2. 请求发出后:

    • 服务器返回响应。
    • 响应拦截器对响应数据进行处理。
    • 如果响应拦截器返回 response,响应数据会传递给业务代码。
    • 如果响应拦截器返回 Promise.reject,错误会传递给业务代码。

4. 总结

  • 请求拦截器:用于在请求发出前对请求进行统一处理,如添加请求头、显示 Loading 状态等。
  • 响应拦截器:用于在接收到响应后对响应进行统一处理,如格式化数据、隐藏 Loading 状态、统一处理错误等。

tailwindcss 是什么?

Tailwind CSS 是一个功能优先的 CSS 框架,提供了大量低级别的实用类,允许开发者直接在 HTML 中通过组合这些类来构建用户界面。与传统的 CSS 框架不同,Tailwind 不提供预定义的组件,而是通过实用类实现高度定制化的设计,同时支持响应式布局、状态变体和 JIT 模式,大幅提升开发效率和性能。

Tailwind CSS 的核心优势在于其灵活性和一致性。开发者可以通过配置文件自定义设计系统,确保项目样式统一,同时避免编写重复的 CSS 代码。尽管学习曲线较陡,且可能导致 HTML 代码臃肿,但 Tailwind CSS 特别适合快速原型开发、定制化设计以及中小型项目。

数组常用的方法?

1. 修改数组的方法

这些方法会直接修改原数组。

  • (1)push():在数组末尾添加一个或多个元素。
  • (2)pop():删除数组的最后一个元素。
  • (3)unshift():在数组开头添加一个或多个元素。
  • (4)shift():删除数组的第一个元素。
  • (5)splice():在指定位置添加或删除元素。
    const arr = [1, 2, 3];
    arr.splice(1, 1, 4); // 从索引 1 开始删除 1 个元素并插入 4,arr 变为 [1, 4, 3]
    
  • (6)reverse():反转数组的顺序。
  • (7)sort():对数组元素进行排序。
    const arr = [3, 1, 2];
    arr.sort(); // arr 变为 [1, 2, 3]
    

2. 不修改原数组的方法

这些方法不会修改原数组,而是返回一个新数组或值。

  • (1)concat():合并两个或多个数组。
  • (2)slice():提取数组的一部分。
    const arr = [1, 2, 3, 4];
    const newArr = arr.slice(1, 3); // newArr 为 [2, 3]
    
  • (3)join():将数组元素连接成一个字符串。
  • (4)indexOf():查找指定元素的第一个索引。
    const arr = [1, 2, 3];
    const index = arr.indexOf(2); // index 为 1
    
  • (5)lastIndexOf():查找指定元素的最后一个索引。
    const arr = [1, 2, 3, 2];
    const index = arr.lastIndexOf(2); // index 为 3
    
  • (6)includes():判断数组是否包含某个元素。

3. 遍历数组的方法

这些方法用于遍历数组元素。

  • (1)forEach():对数组的每个元素执行一次函数。
    const arr = [1, 2, 3];
    arr.forEach(item => console.log(item)); // 依次输出 1, 2, 3
    
  • (2)map():对数组的每个元素执行一次函数,并返回新数组。
    const arr = [1, 2, 3];
    const newArr = arr.map(item => item * 2); // newArr 为 [2, 4, 6]
    
  • (3)filter():过滤数组,返回满足条件的元素组成的新数组。
    const arr = [1, 2, 3];
    const newArr = arr.filter(item => item > 1); // newArr 为 [2, 3]
    
  • (4)reduce():对数组元素执行累加器函数,返回一个累加结果。
    const arr = [1, 2, 3];
    const sum = arr.reduce((acc, item) => acc + item, 0); // sum 为 6
    
  • (5)some():判断数组中是否有元素满足条件。
    const arr = [1, 2, 3];
    const hasEven = arr.some(item => item % 2 === 0); // hasEven 为 true
    
  • (6)every():判断数组中的所有元素是否都满足条件。
    const arr = [1, 2, 3];
    const allEven = arr.every(item => item % 2 === 0); // allEven 为 false
    

4. 其他常用方法

  • (1)find():查找数组中第一个满足条件的元素。
    const arr = [1, 2, 3];
    const result = arr.find(item => item > 1); // result 为 2
    
  • (2)findIndex():查找数组中第一个满足条件的元素的索引。
  • (3)flat():将嵌套数组扁平化。
    const arr = [1, [2, [3]]];
    const newArr = arr.flat(2); // newArr 为 [1, 2, 3]
    
  • (4)flatMap():先对数组元素执行 map(),然后对结果执行 flat(1)。
    const arr = [1, 2, 3];
    const newArr = arr.flatMap(item => [item, item * 2]); // newArr 为 [1, 2, 2, 4, 3, 6]
    

字符串上有什么方法?

1. 查找和截取字符串

  • (1)charAt():返回指定索引位置的字符。
    const str = "Hello";
    console.log(str.charAt(1)); // 'e'
    
  • (2)charCodeAt():返回指定索引位置字符的 Unicode 编码。
  • (3)indexOf():返回指定字符串第一次出现的索引。
    const str = "Hello";
    console.log(str.indexOf('l')); // 2
    
  • (4)lastIndexOf():返回指定字符串最后一次出现的索引。
  • (5)includes():判断字符串是否包含指定子字符串。
  • (6)startsWith():判断字符串是否以指定子字符串开头。
  • (7)endsWith():判断字符串是否以指定子字符串结尾。
  • (8)slice():提取字符串的一部分。
    const str = "Hello";
    console.log(str.slice(1, 3)); // 'el'
    
  • (9)substring():提取字符串的一部分(与 slice() 类似,但不支持负数索引)。
    const str = "Hello";
    console.log(str.substring(1, 3)); // 'el'
    

2. 修改字符串

  • (1)toUpperCase():将字符串转换为大写。
    const str = "Hello";
    console.log(str.toUpperCase()); // 'HELLO'
    
  • (2)toLowerCase():将字符串转换为小写。
  • (3)trim():去除字符串两端的空白字符。
    const str = "  Hello  ";
    console.log(str.trim()); // 'Hello'
    
  • (4)trimStart() / trimLeft():去除字符串开头的空白字符。
  • (5)trimEnd() / trimRight():去除字符串结尾的空白字符。
  • (6)replace():替换字符串中的指定子字符串。
    const str = "Hello";
    console.log(str.replace('He', 'Ha')); // 'Hallo'
    
  • (7)replaceAll():替换字符串中所有匹配的子字符串。

3. 分割和连接字符串

  • (1)split():将字符串按指定分隔符分割成数组。
    const str = "Hello,World";
    console.log(str.split(',')); // ['Hello', 'World']
    
  • (2)concat():连接多个字符串。

4. 其他常用方法

  • (1)repeat():将字符串重复指定次数。
    const str = "Hello";
    console.log(str.repeat(2)); // 'HelloHello'
    
  • (2)padStart():在字符串开头填充指定字符,直到字符串达到指定长度。
    const str = "Hello";
    console.log(str.padStart(10, '*')); // '*****Hello'
    
  • (3)padEnd():在字符串结尾填充指定字符,直到字符串达到指定长度。
  • (4)match():返回字符串中匹配正则表达式的结果。
    const str = "Hello";
    console.log(str.match(/l/g)); // ['l', 'l']
    
  • (5)search():返回字符串中匹配正则表达式的第一个索引。
    const str = "Hello";
    console.log(str.search(/l/)); // 2
    ```**
    

结语

通过这次分享,希望能让你对春招面试有了更清晰的认识和准备。