前端面试全题库(2026 终极版)
初级 / 中级 / 高级分级 + 逐题超详细解析
一、JavaScript 核心
🔰 初级(1–3 年)
1. var / let / const 的区别?
详细解析:
-
作用域不同
var:函数级作用域,只受函数限制,不受{}限制。let/const:块级作用域,if/for/while等{}内有效。
-
变量提升
var:存在变量提升,可以在声明前使用(值为undefined)。let/const:存在提升,但进入暂时性死区 TDZ,声明前使用会报错。
-
重复声明
var:允许重复声明,后面覆盖前面。let/const:同一作用域不允许重复声明。
-
赋值与修改
var/let:可以先声明后赋值,也可重新赋值。const:声明时必须赋值,赋值后不能修改内存地址,但引用类型内部可修改。
最佳实践: 默认使用 const,需要变的用 let,尽量不用 var。
2. JS 数据类型有哪些?存储区别?
详细解析:
7 种基本类型(值类型): String、Number、Boolean、Undefined、Null、Symbol、BigInt
1 种引用类型: Object(包含 Array、Function、Date、RegExp 等)
存储区别:
- 基本类型:存在栈内存,值直接保存,赋值是深拷贝。
- 引用类型:地址存在栈,真实内容存在堆内存,赋值是传地址。
判断方法:
typeof:判断基本类型(除null→object)instanceof:判断引用类型Object.prototype.toString.call(value):最准确
3. == 和 === 的区别?
详细解析:
-
===严格相等:先比较类型,类型不同直接false;类型相同再比较值。 -
==宽松相等:会先进行隐式类型转换,再比较值。转换规则:- 字符串与数字 → 字符串转数字
- 布尔值 → 转数字
null == undefined→true- 对象与基本类型 → 对象转原始类型
注意:
NaN === NaN→false,判断用Number.isNaN()Object.is(NaN, NaN)→true
最佳实践: 项目中一律使用 ===。
4. 数组常用方法,哪些改变原数组?
详细解析:
不改变原数组(常用):
map:遍历返回新数组filter:过滤返回新数组reduce:累计计算concat:拼接slice:截取forEach:仅遍历
改变原数组:
push/popshift/unshiftsplicesortreverse
📌 中级(3–5 年)
5. 原型与原型链详解?
详细解析:
1)原型 prototype:每个函数都有 prototype 显式原型,是一个对象,存放共享属性和方法。
2)__proto__:每个对象都有 __proto__ 隐式原型,指向其构造函数的 prototype。
3)原型链:对象通过 __proto__ 向上查找属性 / 方法,直到 null,这条链叫原型链。
4)作用:
- 实现继承
- 方法共享,节省内存
- 实现 JS 面向对象
经典关系:
对象.__proto__ === 构造函数.prototype
构造函数.prototype.constructor === 构造函数
6. this 指向完整规则?
详细解析:
1)默认绑定:全局 / 独立函数调用,非严格模式 → window;严格模式 → undefined
2)隐式绑定:对象方法调用 → 谁调用指向谁
3)显式绑定:call / apply / bind → 指向第一个参数
4)new 绑定:new Fn() → 指向新创建的实例对象
5)箭头函数:没有自己的 this,继承外层作用域的 this,且无法被修改。
优先级: new > 显式绑定 > 隐式绑定 > 默认绑定
7. 闭包是什么?应用与缺点?
详细解析:
定义: 函数嵌套函数,内部函数引用了外部函数的变量 / 参数,就形成闭包。
作用:
- 私有化变量,避免全局污染
- 形成模块化
- 柯里化、防抖节流保存状态
- 工厂函数、迭代器
缺点: 变量常驻内存,使用不当会造成内存泄漏。
解决:
- 不用时手动解除引用
fn = null - 避免在循环中创建闭包
8. 浏览器事件循环完整机制?
详细解析:
执行顺序:
- 执行全局同步代码
- 执行微任务队列(清空所有)
- 执行渲染(若需要)
- 取一个宏任务执行
- 回到步骤 2,循环
微任务(优先级高): Promise.then / catch / finally、queueMicrotask、async / await、MutationObserver
宏任务: script、setTimeout、setInterval、I/O、UI 渲染、requestAnimationFrame
经典面试题口诀: 同步先跑,微任务全清,再跑一个宏任务。
9. 浅拷贝与深拷贝?实现方式?
详细解析:
浅拷贝: 只复制第一层,深层引用类型共享地址。实现:
Object.assign- 展开运算符
{...obj} Array.prototype.slice/concat
深拷贝: 递归复制所有层级,完全独立。实现:
JSON.parse(JSON.stringify(obj)):缺点是不能复制函数、undefined、Symbol、循环引用- 手写递归深拷贝(处理循环引用、函数、Date 等)
🚀 高级(5 年 +/ 架构)
10. Promise A+ 规范与原理?
详细解析:
三大状态:
pending→ 初始fulfilled→ 成功rejected→ 失败
状态一旦改变,不可逆。
核心方法:
then:返回新 Promise,支持链式catch:捕获异常finally:无论如何都执行
静态方法:
Promise.all:全部成功才成功,一个失败即失败Promise.race:谁先完成就用谁Promise.allSettled:全部返回结果(不管成败)Promise.resolve/reject
手写要点:
- 状态管理
- 发布订阅(存成功 / 失败回调)
- 微任务模拟
- 链式调用返回新 Promise
11. async / await 原理?
详细解析:
本质: async / await 是 Generator + 自动执行器 的语法糖。
执行流程:
async函数返回一个 Promiseawait后面通常是 Promise- 等待 Promise resolve 后继续执行
- 异常需要用
try/catch捕获
优点:
- 同步写法,解决回调地狱
- 代码可读性极高
12. 手写防抖(详细带注释)
/**
* 防抖:频繁触发时,只在最后一次触发后 delay 毫秒执行
* @param {Function} fn 执行函数
* @param {number} delay 延迟毫秒
* @returns {Function}
*/
function debounce(fn, delay) {
let timer = null;
return function(...args) {
// 清除之前的定时器
if (timer) clearTimeout(timer);
// 重新计时
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
};
}
场景: 搜索输入、窗口 resize、表单验证
13. 手写节流(详细带注释)
/**
* 节流:固定时间内只执行一次
* @param {Function} fn
* @param {number} interval
* @returns {Function}
*/
function throttle(fn, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
lastTime = now;
fn.apply(this, args);
}
};
}
场景: 滚动加载、高频点击、游戏射击
14. V8 垃圾回收机制?
详细解析:
分代回收:
- 新生代:存活时间短,使用
Scavenge复制算法 - 老生代:存活时间长,使用
Mark-Sweep(标记清除)+Mark-Compact(标记整理)
垃圾回收流程:
- 根节点遍历(全局、调用栈)
- 标记可达对象
- 清除未标记对象
- 整理内存(减少碎片)
常见内存泄漏:
- 意外全局变量
- 闭包滥用
- 未清理的定时器 / 事件监听
- DOM 引用未释放
二、CSS 模块
🔰 初级
1. 标准盒模型与怪异盒模型?
详细解析:
标准盒模型(content-box)
box-sizing: content-box
width = content 宽度
怪异盒模型(border-box)
box-sizing: border-box
width = content + padding + border
项目中通用:
* {
box-sizing: border-box;
}
2. CSS 选择器优先级?
详细解析:
优先级权重公式(从高到低):
!important > 行内样式 > ID > 类/属性/伪类 > 元素/伪元素
计算规则:
- 行内:1000
- ID:100
- 类 / 属性 / 伪类:10
- 元素 / 伪元素:1
注意:
- 权重相同,后写的覆盖先写的
- 继承样式优先级最低
!important尽量少用,难以覆盖
3. 水平垂直居中 3 种方法?
详细解析:
1)flex(最常用)
.parent {
display: flex;
justify-content: center;
align-items: center;
}
2)绝对定位 + transform
.parent { position: relative; }
.child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
3)grid
.parent {
display: grid;
place-items: center;
}
📌 中级
4. BFC 原理、触发条件、应用?
详细解析:
BFC:块级格式化上下文,独立渲染区域,内部布局不影响外部。
触发条件(任一):
float不为noneposition: absolute/fixedoverflow不为visibledisplay: inline-block/flex/grid/table-cell
应用:
- 清除浮动,解决高度塌陷
- 解决垂直方向 margin 重叠
- 两栏自适应布局
5. flex 核心属性?
详细解析:
容器属性:
flex-direction:主轴方向justify-content:主轴对齐align-items:交叉轴对齐flex-wrap:是否换行align-content:多行对齐
项目属性:
flex-grow:放大比例flex-shrink:缩小比例flex-basis:基础宽度flex:缩写flex: 1最常用align-self:自身单独对齐
6. 重排 reflow 与重绘 repaint?
详细解析:
重排(布局): 元素几何尺寸、位置变化 → 重新计算布局 → 性能消耗大
重绘(样式): 颜色、背景等变化,不影响布局 → 消耗较小
触发重排:
- 窗口 resize
- 增删 DOM
- 修改宽高、边距、定位
- 获取
offsetTop/scrollLeft等(强制同步布局)
优化:
- 使用
transform/opacity(合成层,不触发重排) - 批量修改 DOM(先隐藏再修改)
- 读写分离
- 使用文档碎片
DocumentFragment
🚀 高级
7. 层叠上下文与 z-index?
详细解析:
层叠上下文: 相当于一个 3D 栈,控制元素垂直堆叠顺序。
创建条件:
position不为 static 且z-index不为 autoopacity < 1transform/filter不为 noneflex子项且z-index不为 auto
层叠等级(从下到上):
- 背景与边框
- 负 z-index
- 块级 / 行内 / 浮动
z-index: 0/auto- 正 z-index
注意: 子元素 z-index 只在父层叠上下文内比较。
8. CSS 模块化方案对比?
详细解析:
1)CSS Modules
- 编译生成唯一哈希类名
- 无全局污染
- 适合 React 项目
2)Scoped CSS
- Vue 默认
- 原理:添加
data-v-hash属性选择器 - 子组件根元素受父 scoped 影响
3)CSS-in-JS
- styled-components / emotion
- 动态性极强
- 缺点:运行时开销、调试稍难
4)BEM 命名
- 手动规范命名
- 无工具依赖
三、Vue 模块
🔰 初级
1. Vue2 生命周期?
详细解析:
创建阶段:
beforeCreate:数据观测未开始created:能访问 data/methods,常用于异步请求
挂载阶段:
beforeMount:模板编译完成,未挂载mounted:DOM 已生成,可操作 DOM
更新阶段:
beforeUpdateupdated
销毁阶段:
beforeDestroy:清除定时器、事件监听destroyed
2. v-if 与 v-show 区别?
详细解析:
v-if:
- 真正的销毁 / 重建
- 切换开销大
- 初始不渲染
- 可配合
template - 适合不频繁切换
v-show:
- 只是
display: none - 初始渲染开销大
- 频繁切换优先用 v-show
3. Vue 组件通信 7 种?
详细解析:
- 父 → 子:props
- 子 → 父:$emit
- 父子链:children(不推荐)
- 跨级:provide / inject
- 兄弟:eventBus
- 全局:Vuex / Pinia
- 边界:listeners
📌 中级
4. Vue2 响应式原理?
详细解析:
核心: Object.defineProperty
遍历对象属性,劫持 get(收集依赖)、set(触发更新)。
缺点:
- 无法监听对象新增 / 删除属性
- 无法监听数组下标修改、
length修改
解决方案:
Vue.set(target, key, value)Vue.delete- 重写数组 7 个方法:push / pop / shift / unshift / splice / sort / reverse
5. Vue3 响应式原理?
详细解析:
核心: Proxy + Reflect
- 代理整个对象,而非单个属性
- 支持监听新增 / 删除属性
- 支持监听数组下标、length
- 支持嵌套对象懒监听
优势:
- 性能更好
- 更完整
- 支持 Map / Set / WeakMap 等
6. v-for 中 key 的作用?为什么不能用 index?
详细解析:
作用: 给 Diff 算法提供唯一标识,让 Vue 精准复用节点,减少 DOM 操作。
为什么不要用 index:
- 数组顺序变化时,index 会变
- 导致节点错误复用、渲染错乱
- 列表带状态(复选框、输入框)时必出问题
最佳实践: 使用后端返回的唯一 id。
🚀 高级
7. Vue Diff 算法核心逻辑?
详细解析:
原则:
- 只做同层比较,不跨级
- 深度优先
双端比较流程:
- 旧头 ↔ 新头
- 旧尾 ↔ 新尾
- 旧头 ↔ 新尾
- 旧尾 ↔ 新头
- 建立映射表,快速查找
优化:
- 尽量复用 DOM
- 移动而非删除重建
- key 是关键
8. Composition API 优势?
详细解析:
- 逻辑复用更优雅:替代 mixin,无命名冲突、来源清晰
- 代码组织更聚合:按功能组织,而非按 options 分片
- TS 类型推导友好:无复杂的 this 类型问题
- 更好的 tree shaking:按需引入,体积更小
- 无生命周期混乱,逻辑可独立提取
9. Vue 项目性能优化?
详细解析:
编码层面:
- v-show 替换频繁切换 v-if
- v-for 必加 key,避免 index
- 计算属性缓存复杂计算
- 防抖节流处理高频事件
打包层面:
- 路由懒加载
- 异步组件
- 图片懒加载
- 开启 gzip
- splitChunks 拆分 vendor
运行层面:
- 虚拟列表处理长列表
- 销毁时清除定时器 / 监听
- 使用
keep-alive缓存页面
四、React 模块
🔰 初级
1. 类组件 vs 函数组件?
详细解析:
类组件:
- 有 state、生命周期、this
- 代码量大
- 逻辑复用麻烦(HOC、render-props)
函数组件:
- 简洁、无 this 困扰
- Hooks 后可完全替代类组件
- 性能更好,更容易被优化
趋势: 全面拥抱函数组件 + Hooks。
2. state 与 props 区别?
详细解析:
props:
- 父组件传入
- 只读,不可修改
- 用于父子通信
state:
- 组件内部私有
- 可修改,
setState异步更新 - 修改后触发重渲染
原则: 单向数据流:父 → 子
3. React 合成事件?
详细解析:
React 不使用原生事件,而是自己封装合成事件 SyntheticEvent。
优势:
- 浏览器兼容性抹平
- 事件委托到
document,减少内存开销 - 批量更新,性能优化
- 事件对象可复用(池化)
注意:
- 异步中要取事件值需
event.persist() - 原生事件与合成事件可共存但要注意执行顺序
📌 中级
4. useEffect 完整机制?
详细解析:
useEffect(() => {
// 执行副作用
return () => {
// 清除副作用(下一次执行前 or 卸载)
}
}, [依赖])
依赖规则:
- 无依赖数组:每次渲染都执行
- 空数组
[]:仅挂载、卸载执行 - 有依赖:依赖变化执行
常见用途:
- 数据请求
- 事件监听
- 订阅
- DOM 操作
5. Hooks 规则?
详细解析:
- 只在顶层调用:不能在循环、条件、嵌套函数中调用
- 只在 React 函数组件 / 自定义 Hook 中调用
- 依赖数组必须真实:必须包含所有外部变量
违反规则会导致状态混乱、闭包陷阱。
6. React.memo / useMemo / useCallback?
详细解析:
React.memo:
- 缓存组件
- 浅比较 props
- 避免子组件不必要重渲染
useMemo:
- 缓存计算结果
- 避免重复计算
const value = useMemo(() => compute(a, b), [a, b])
useCallback:
- 缓存函数引用
- 传给子组件时避免重渲染
const fn = useCallback(() => {}, [])
🚀 高级
7. Fiber 架构解决了什么?
详细解析:
旧架构问题: 同步递归渲染,一旦开始无法中断,大量计算会阻塞主线程 → 页面卡顿。
Fiber 解决:
- 可中断、可恢复、可优先级调度
- 把渲染拆分成小 Fiber 单元
- 基于链表遍历(child / sibling / return)
- 支持时间切片,给浏览器渲染留时间
- 支持并发特性:Suspense、Transitions
8. React vs Vue 核心差异?
详细解析:
响应式:
- Vue:基于 Proxy 自动收集依赖,精确更新
- React:基于状态不可变,标记更新,全量对比调和
编写方式:
- Vue:模板 + 选项式 / 组合式
- React:JSX 全 JS
更新机制:
- Vue:push 式更新,精准
- React:pull 式,需要手动优化(memo 等)
生态定位:
- Vue:渐进式,易用优先
- React:灵活强大,工程化优先
五、TypeScript 模块
🔰 初级
1. TS 相比 JS 的优势?
详细解析:
- 静态类型检查:编译时发现错误,减少线上 Bug
- 智能提示与重构:IDE 支持极强,大型项目必备
- 可读性与可维护性:类型即文档
- 面向对象更完善:接口、泛型、装饰器
- 兼容 ES 最新特性,编译可指定目标版本
2. TS 基础类型?
详细解析:
原始:string、number、boolean、undefined、null
特殊:any、unknown、void、never
引用:object、array、tuple、enum
any vs unknown:
any:关闭类型检查,不安全unknown:安全,必须类型判断后使用
📌 中级
3. interface vs type 区别?
详细解析:
interface:
- 描述对象 / 类
- 支持
extends继承 - 支持自动合并
- 适合公共 API 定义
type:
- 更强大,支持联合、交叉、元组、工具类型
- 不可重复定义
- 适合复杂类型组合
通用建议:
- 定义对象 / 类用 interface
- 复杂类型、工具类型用 type
4. 泛型作用与示例?
详细解析:
作用: 不预先指定类型,在使用时动态指定,实现类型安全 + 复用。
function identity<T>(arg: T): T {
return arg;
}
const str = identity<string>('abc');
const num = identity(123); // 自动推导
常见:Promise<T>、Array<T>、useState<T>
🚀 高级
5. 内置工具类型原理?
详细解析:
Partial<T> // 所有属性可选
Required<T> // 所有属性必选
Readonly<T> // 只读
Pick<T, K> // 挑选部分属性
Omit<T, K> // 排除部分属性
Exclude<T, U> // 从 T 排除 U
Extract<T, U> // 提取 T 与 U 交集
ReturnType<T> // 获取函数返回值类型
基于映射类型与条件类型实现。
6. 类型守卫?
详细解析:
用于缩小类型范围,让 TS 精准判断。
1)typeof
if (typeof val === 'string') {}
2)instanceof
if (val instanceof Date) {}
3)in
if ('name' in obj) {}
4)自定义类型谓词
function isUser(user: any): user is User {
return user && typeof user.id === 'number';
}
六、工程化
🔰 初级
1. npm / yarn / pnpm 区别?
详细解析:
npm:
- 官方
- 早期依赖地狱、嵌套严重
- npm5 后 package-lock.json
yarn:
- 并行安装、缓存、lock 稳定
pnpm:
- 基于硬链接 + 符号链接
- 速度极快、极省空间
- 严格依赖,避免幽灵依赖
趋势: 现代项目优先 pnpm。
2. Loader vs Plugin?
详细解析:
Loader:
- 模块转换器
- 处理非 JS 文件:css、ts、图片、vue
- 执行在 module 解析阶段
Plugin:
- 扩展 webpack 能力
- 基于事件钩子
- 打包优化、资源管理、注入变量
📌 中级
3. Webpack 构建流程?
详细解析:
- 初始化:读取配置,实例化
Compiler - 开始编译:
run→make - 构建依赖图:从 entry 开始,递归依赖,使用 loader 转译
- 生成 chunk:根据依赖关系分组
- 输出 bundle:写入文件系统
核心钩子:entryOption、compile、make、seal、emit
4. Vite 为什么快?
详细解析:
开发环境:
- 基于原生 ES Module(ESM)
- 不打包,浏览器按需请求
esbuild预构建依赖,极快
生产环境:
- 使用 Rollup 打包
- 输出产物更优
优势:
- 冷启动极快
- 热更新秒级
- 配置简单
🚀 高级
5. Tree Shaking 原理与条件?
详细解析:
原理: 基于 ES Module 静态结构分析,移除未引用代码。
条件:
- 必须是 ESM(import / export)
- production 模式
- 无副作用(
sideEffects: false) - 代码不被动态引用
6. 微前端核心思想?
详细解析:
目标:
- 多技术栈共存
- 独立开发、独立部署
- 运行时隔离
核心能力:
- 路由分发
- JS 沙箱(快照 / Proxy)
- 样式隔离(CSS Modules / Shadow DOM)
- 应用间通信
代表: qiankun、single-spa、Module Federation
七、网络
🔰 初级
1. GET vs POST?
详细解析:
语义:
- GET:获取资源,安全、幂等
- POST:提交资源,非幂等
参数:
- GET:URL 中,长度受限
- POST:请求体,容量大
缓存:
- GET 可被缓存
- POST 默认不缓存
安全: 都不安全,都需 HTTPS。
2. HTTP 状态码?
详细解析:
1xx:信息 2xx:成功(200) 3xx:重定向(301/302/304) 4xx:客户端错(400/401/403/404) 5xx:服务端错(500/502/504)
📌 中级
3. 强缓存 vs 协商缓存?
详细解析:
强缓存: 不发请求,直接读缓存
Cache-Control: max-age=xxxExpires
协商缓存: 发请求,服务端验证
Last-Modified/If-Modified-SinceETag/If-None-Match
返回 304 则用缓存
4. 跨域原因与解决方案?
详细解析:
原因: 浏览器同源策略(协议、域名、端口一致),防止 CSRF/XSS。
解决方案:
- CORS(服务端配置)
- JSONP(仅 GET)
- 代理服务器(webpack devServer、nginx)
postMessage- WebSocket
🚀 高级
5. HTTP/1.1 / HTTP/2 / HTTP/3?
详细解析:
HTTP/1.1:
- 长连接
- 队头阻塞
- 多个 TCP 连接
HTTP/2:
- 多路复用(单连接多流)
- 头部压缩 HPACK
- 服务器推送
HTTP/3:
- 基于 QUIC(UDP)
- 彻底解决队头阻塞
- 0-RTT 握手
6. HTTPS 流程?
详细解析:
- 客户端发起请求
- 服务端返回证书
- 客户端验证证书合法性
- 客户端生成随机预主密钥
- 用公钥加密发给服务端
- 双方计算出会话密钥
- 后续通信对称加密
八、安全
🔰 初级
1. XSS 攻击?
详细解析:
跨站脚本攻击,注入恶意脚本,窃取 Cookie、伪造请求、劫持账号。
分类:
- 存储型(存入数据库)
- 反射型(URL 参数)
- DOM 型(前端直接渲染)
2. CSRF 攻击?
详细解析:
跨站请求伪造,利用用户登录态,在第三方网站发起请求,执行未授权操作。
📌 中级
3. XSS 防御?
详细解析:
- 输入过滤
- 输出转义(< → <)
- CSP 内容安全策略
HttpOnlyCookieSameSiteCookie
4. CSRF 防御?
详细解析:
- CSRF Token
SameSite=Strict/Lax- 验证 Referer / Origin
- 敏感操作二次验证
🚀 高级
5. CSP 工作原理?
详细解析:
通过 HTTP 头或 meta 标签,限制资源加载来源:
- 限制脚本、样式、图片、字体
- 禁止内联脚本
- 禁止 eval
大幅降低 XSS 危害。
九、算法与数据结构
🔰 初级
1. 数组去重?
详细解析:
// ES6
[...new Set(arr)]
// 遍历
function unique(arr) {
const res = [];
const map = {};
for(let v of arr) {
if(!map[v]) {
map[v] = true;
res.push(v);
}
}
return res;
}
2. 冒泡排序?
function bubbleSort(arr) {
let len = arr.length;
for(let i = 0; i < len - 1; i++) {
for(let j = 0; j < len - i - 1; j++) {
if(arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return arr;
}
复杂度 O(n²)
📌 中级
3. 有效的括号?
function isValid(s) {
const stack = [];
const map = { ')': '(', '}': '{', ']': '[' };
for(let c of s) {
if(!map[c]) stack.push(c);
else {
if(stack.pop() !== map[c]) return false;
}
}
return stack.length === 0;
}
4. 两数之和?
function twoSum(nums, target) {
const map = new Map();
for(let i = 0; i < nums.length; i++) {
const diff = target - nums[i];
if(map.has(diff)) {
return [map.get(diff), i];
}
map.set(nums[i], i);
}
return [];
}
O(n)
🚀 高级
5. 快速排序?
function quickSort(arr) {
if(arr.length <= 1) return arr;
const pivot = arr[0];
const left = [];
const right = [];
for(let i = 1; i < arr.length; i++) {
if(arr[i] < pivot) left.push(arr[i]);
else right.push(arr[i]);
}
return [...quickSort(left), pivot, ...quickSort(right)];
}
平均 O(nlogn)
6. 反转链表?
function reverseList(head) {
let prev = null;
let cur = head;
while(cur) {
const next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
}