| 概念 | 作用 | 配置位置 | 典型场景 |
|---|---|---|---|
| Entry | 指定打包入口 |
entry | 单页应用:单入口 多页应用:多入口 |
| Output | 指定输出配置 |
output | 配置文件名、路径、公共路径 |
| Loader | 转换非 JS 模块 |
module.rules | 处理 CSS、图片、TS、JSX |
| Plugin | 扩展功能 |
plugins | 压缩、生成 HTML、分析打包 |
| Mode | 构建模式 |
mode | development / production |
| Resolve | 模块解析 |
resolve | 别名、扩展名、查找路径 |
| Optimization | 优化配置 |
optimization | 代码分割、压缩、Tree Shaking |
单入口:
module.exports = {
entry: './src/index.js',
}
多入口:
module.exports = {
entry: {
app: './src/app.js',
admin: './src/admin.js',
},
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
},
}
| Loader | 作用 | 配置示例 |
|---|---|---|
| babel-loader | 转译 ES6+ |
{ test: /.jsx?$/, use: 'babel-loader' } |
| ts-loader | 转译 TS |
{ test: /.tsx?$/, use: 'ts-loader' } |
| css-loader | 解析 CSS |
{ test: /.css$/, use: ['style-loader', 'css-loader'] } |
| sass-loader | 编译 Sass |
use: ['style-loader', 'css-loader', 'sass-loader'] |
| url-loader | 小文件 Base64 |
{ type: 'asset', parser: { dataUrlCondition: { maxSize: 8192 } } } |
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
},
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
],
}
module.exports = {
cache: {
type: 'filesystem',
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[/]node_modules[/]/,
name: 'vendors',
priority: 10,
},
},
},
},
}
| 对比维度 | Vite | Webpack |
|---|---|---|
| 启动速度 | ⚡ 极快(无需打包) | 🐢 慢(需打包) |
| 热更新 | ⚡ 秒级 | 🐢 较慢 |
| 生产构建 | Rollup | 自身 |
| 配置 | ✅ 简单 | ❌ 复杂 |
// vite.config.js
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': '/src',
},
},
server: {
port: 3000,
proxy: {
'/api': 'http://localhost:8080',
},
},
build: {
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
},
},
},
},
})
| 模块 | 用途 | 常用 API |
|---|---|---|
| fs | 文件系统 |
readFile(),
writeFile(),
mkdir() |
| path | 路径处理 |
join(),
resolve(),
dirname() |
| http | HTTP 服务 |
createServer(),
request() |
| stream | 流处理 |
Readable,
Writable,
pipe() |
| events | 事件处理 |
EventEmitter,
on(),
emit() |
const fs = require('fs').promises
// 读取文件
async function readConfig() {
const data = await fs.readFile('config.json', 'utf8')
return JSON.parse(data)
}
// 写入文件
async function writeConfig(config) {
await fs.writeFile('config.json', JSON.stringify(config, null, 2))
}
const EventEmitter = require('events')
class OrderService extends EventEmitter {
createOrder(data) {
const order = { id: Date.now(), ...data }
this.emit('orderCreated', order)
return order
}
}
const service = new OrderService()
service.on('orderCreated', (order) => {
console.log('订单已创建:', order)
})
| 分类 | 核心作用 | 典型接口 / 对象 | 使用场景示例 | 所属环境 |
|---|---|---|---|---|
| JavaScript 内置 API | 提供编程语言基础功能(数据处理、逻辑运算等) |
String(
slice()、
toUpperCase())、
Array(
map()、
filter())、
Object(
keys())、
Date(
getFullYear())、
Math(
random())、
JSON(
parse()、
stringify()) | - 用
Array.map() 处理数组数据- 用
JSON.parse() 解析接口返回的 JSON 字符串- 用
Math.random() 生成随机数 | 独立于浏览器(Node.js/ 浏览器均支持) |
| DOM API | 操作网页文档的结构、内容和样式 |
document(
querySelector()、
createElement())、
element(
appendChild()、
setAttribute())、
Event(
addEventListener()) | - 通过
document.getElementById() 获取元素- 用
element.classList.add() 添加 CSS 类- 用
addEventListener() 绑定点击事件 | 浏览器环境(Web API 子集) |
| BOM API | 操作浏览器窗口及基础功能 |
window(
alert()、
scrollTo())、
location(
href、
reload())、
history(
back()、
pushState())、
navigator(
userAgent) | - 用
window.alert() 弹出提示框- 通过
location.href 跳转页面- 用
history.back() 回退历史 | 浏览器环境(Web API 子集) |
| 网络 API | 处理网络请求与数据交互(含 Socket 实时通信) |
fetch()、
XMLHttpRequest、
WebSocket(Socket 全双工通信)、
AbortController | - 用
fetch() 调用后端接口- 用
WebSocket 实现 Socket 实时通信(如在线聊天、实时数据推送)- 用
AbortController 取消请求 | 浏览器环境(Web API 子集) |
| 存储 API | 在浏览器中存储数据(本地 / 会话) |
localStorage、
sessionStorage、
Cookie、
IndexedDB | - 用
localStorage 存储用户偏好设置- 用
IndexedDB 存储大量结构化数据 | 浏览器环境(Web API 子集) |
| 设备 API | 与用户设备硬件交互 |
navigator.geolocation(地理位置)、
MediaDevices(摄像头 / 麦克风)、
BatteryStatus(电池状态) | - 获取用户位置并显示在地图上- 调用摄像头进行视频拍摄- 检测设备电池电量 | 浏览器环境(Web API 子集) |
| 时间 / 动画 API | 处理时间控制与动画效果 |
setTimeout()、
setInterval()、
requestAnimationFrame()、
performance | - 用
requestAnimationFrame() 实现平滑动画- 用
performance 计算页面加载时间 | 浏览器环境(Web API 子集) |
| 音频 / 视频 API | 处理音视频播放与控制 |
HTMLMediaElement、
MediaRecorder、
Web Audio API | - 自定义视频播放器(控制播放 / 暂停)- 用
MediaRecorder 录制音频 | 浏览器环境(Web API 子集) |
| 安全 / 权限 API | 管理浏览器权限与安全相关功能 |
Permissions API、
Content Security Policy (CSP)、
Crypto(加密) | - 检测用户是否授予摄像头权限- 用
Crypto 对敏感数据加密 | 浏览器环境(Web API 子集) |
| Canvas API | 绘制 2D/3D 图形、动画及图像处理 |
HTMLCanvasElement、
CanvasRenderingContext2D、
WebGLRenderingContext(3D) | - 用 2D 上下文绘制图表、签名板- 用 WebGL 实现 3D 游戏场景- 实时处理摄像头采集的图像 | 浏览器环境(Web API 子集) |
| HTML API | 操作 HTML 元素特性与行为(原生组件增强) |
HTMLInputElement(表单输入)、
HTMLDialogElement(对话框)、
HTMLDetailsElement(折叠面板)、
IntersectionObserver(元素可见性检测) | - 用
HTMLDialogElement 实现原生弹窗- 用
IntersectionObserver 检测元素进入视口(懒加载) | 浏览器环境(Web API 子集) |
| CSS API | 操作 CSS 样式与动画 |
CSSStyleDeclaration(元素样式)、
CSSKeyframesRule(关键帧动画)、
CSSOM(CSS 对象模型) | - 用
element.style 动态修改元素样式- 用 JS 动态创建 CSS 关键帧动画- 通过
getComputedStyle() 获取计算后样式 | 浏览器环境(Web API 子集) |
| 拖拽 API | 实现元素拖拽功能 |
DragEvent、
dataTransfer 对象 | - 实现文件拖拽上传- 拖拽排序列表项- 跨元素传递数据 | 浏览器环境(Web API 子集) |
| 通知 API | 向用户发送系统级通知(需权限) |
Notification 对象 | - 网页后台消息通知- 任务完成提醒- 实时消息推送 | 浏览器环境(Web API 子集) |
| Worker API | 开启后台线程,避免阻塞主线程 |
Web Worker、
Service Worker(离线缓存)、
SharedWorker(多页面共享) | - 用
Web Worker 处理大量数据计算- 用
Service Worker 实现网页离线访问 | 浏览器环境(Web API 子集) |
| API | 容量 | 数据类型 | 生命周期 | 场景 |
|---|---|---|---|---|
| localStorage | 5-10MB | String | 永久 | 用户设置 |
| sessionStorage | 5-10MB | String | 会话 | 临时数据 |
| IndexedDB | >250MB | 结构化 | 永久 | 大量数据 |
| Cookie | 4KB | String | 可设置 | 身份认证 |
// 存储
localStorage.setItem('user', JSON.stringify({ name: '张三' }))
// 读取
const user = JSON.parse(localStorage.getItem('user'))
// 监听变化
window.addEventListener('storage', (e) => {
console.log('键:', e.key)
console.log('新值:', e.newValue)
})
// GET 请求
async function getUsers() {
const response = await fetch('/api/users', {
headers: {
Authorization: `Bearer ${token}`,
},
})
return response.json()
}
// POST 请求
async function createUser(data) {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
return response.json()
}
| Hook | 用途 | 场景 | 注意事项 |
|---|---|---|---|
| useState | 状态管理 | 组件状态 | 异步更新 |
| useEffect | 副作用 | 数据获取、订阅 | 依赖数组 |
| useContext | 跨组件传值 | 全局状态 | 避免过度使用 |
| useCallback | 缓存函数 | 传递回调 | 配合 memo |
| useMemo | 缓存值 | 昂贵计算 | 不要过度优化 |
| useRef | 引用 DOM | 获取节点 | 不触发渲染 |
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
// 函数式更新
const increment = () => {
setCount((prev) => prev + 1)
}
// 对象状态
const [form, setForm] = useState({ name: '', email: '' })
const updateField = (field, value) => {
setForm((prev) => ({
...prev,
[field]: value,
}))
}
return <div>{count}</div>
}
import { useEffect, useState } from 'react'
function UserProfile({ userId }) {
const [user, setUser] = useState(null)
useEffect(() => {
let cancelled = false
async function fetchUser() {
const response = await fetch(`/api/users/${userId}`)
const data = await response.json()
if (!cancelled) {
setUser(data)
}
}
fetchUser()
return () => {
cancelled = true
}
}, [userId])
return <div>{user?.name}</div>
}
// useLocalStorage.js
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const item = localStorage.getItem(key)
return item ? JSON.parse(item) : initialValue
})
const setStoredValue = (newValue) => {
setValue(newValue)
localStorage.setItem(key, JSON.stringify(newValue))
}
return [value, setStoredValue]
}
// 使用
function App() {
const [theme, setTheme] = useLocalStorage('theme', 'light')
return <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>切换主题</button>
}
HTML → DOM 树
CSS → CSSOM 树
↓
渲染树(Render Tree)
↓
布局(Layout/Reflow)
↓
绘制(Paint/Repaint)
↓
合成(Composite)
| 优化项 | 方法 | 效果 |
|---|---|---|
| 减少重排 | 读写分离、批量操作 | 避免强制同步布局 |
| 减少重绘 | 使用 CSS 类 | 合并样式修改 |
| GPU 加速 |
transform,
opacity | 跳过重排/重绘 |
| 虚拟滚动 | react-window | 减少 DOM 节点 |
| 代码分割 | 懒加载 | 减少首屏加载 |
| 威胁 | 攻击方式 | 防御措施 |
|---|---|---|
| XSS | 注入恶意脚本 | 输入验证、CSP、HttpOnly |
| CSRF | 伪造请求 | CSRF Token、SameSite |
| SQL 注入 | 恶意 SQL | 参数化查询、ORM |
// 转义 HTML
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"'
}
return text.replace(/[&<>"]/g, (char) => map[char])
}
// CSP 配置
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' https://trusted-cdn.com;
">
// CSRF Token
const token = crypto.randomBytes(32).toString('hex')
fetch('/api/transfer', {
method: 'POST',
headers: {
'X-CSRF-Token': token,
},
body: JSON.stringify({ amount: 100 }),
})
| 模式 | 核心思想 | 前端应用 |
|---|---|---|
| 单例 | 全局唯一实例 | Store、Logger |
| 观察者 | 一对多通知 | 事件系统 |
| 发布订阅 | 解耦通信 | EventBus |
| 策略 | 封装算法 | 表单验证 |
| 装饰器 | 扩展功能 | HOC |
class Store {
constructor() {
if (Store.instance) {
return Store.instance
}
this.state = {}
Store.instance = this
}
getState() {
return this.state
}
setState(newState) {
this.state = { ...this.state, ...newState }
}
}
const store1 = new Store()
const store2 = new Store()
console.log(store1 === store2) // true
class EventBus {
constructor() {
this.events = {}
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = []
}
this.events[event].push(callback)
}
emit(event, data) {
this.events[event]?.forEach((cb) => cb(data))
}
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter((cb) => cb !== callback)
}
}
}
// ❌ 代码重复
function formatUserName(user) {
return user.firstName + ' ' + user.lastName
}
function formatAdminName(admin) {
return admin.firstName + ' ' + admin.lastName
}
// ✅ 提取公共函数
function formatFullName(person) {
return `${person.firstName} ${person.lastName}`
}
| 原则 | 全称 | 核心思想 |
|---|---|---|
| S | Single Responsibility | 单一职责 |
| O | Open/Closed | 对扩展开放,对修改关闭 |
| L | Liskov Substitution | 子类可替换父类 |
| I | Interface Segregation | 接口隔离 |
| D | Dependency Inversion | 依赖倒置 |
单一职责示例:
// ❌ 违反 SRP
function UserProfile({ userId }) {
const [user, setUser] = useState(null)
useEffect(() => {
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then(setUser)
}, [userId])
return <div>{user?.name}</div>
}
// ✅ 符合 SRP
function useUser(userId) {
const [user, setUser] = useState(null)
useEffect(() => {
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then(setUser)
}, [userId])
return user
}
function UserProfile({ userId }) {
const user = useUser(userId)
return <div>{user?.name}</div>
}
// ❌ 组件知道太多层级
function OrderSummary({ order }) {
return <div>{order.user.profile.name}</div>
}
// ✅ 只依赖直接 Props
function OrderSummary({ userName }) {
return <div>{userName}</div>
}
src/
├── components/ # UI 层
├── hooks/ # 业务逻辑层
├── services/ # 数据层
├── models/ # 数据模型
└── utils/ # 工具函数
示例:
// 数据层
// services/userService.js
export const userService = {
async getUser(userId) {
const response = await fetch(`/api/users/${userId}`)
return response.json()
},
}
// 业务逻辑层
// hooks/useUser.js
export function useUser(userId) {
const [user, setUser] = useState(null)
useEffect(() => {
userService.getUser(userId).then(setUser)
}, [userId])
return user
}
// UI 层
// components/UserProfile.jsx
export function UserProfile({ userId }) {
const user = useUser(userId)
return <div>{user?.name}</div>
}
主应用:
import { registerMicroApps, start } from 'qiankun'
registerMicroApps([
{
name: 'app1',
entry: '//localhost:7001',
container: '#subapp',
activeRule: '/app1',
},
])
start()
子应用:
// 生命周期
export async function bootstrap() {
console.log('bootstrap')
}
export async function mount(props) {
console.log('mount', props)
render(props)
}
export async function unmount() {
console.log('unmount')
}
src/
├── domains/
│ ├── user/ # 用户领域
│ │ ├── model/
│ │ ├── service/
│ │ └── repository/
│ └── order/ # 订单领域
│ ├── model/
│ ├── service/
│ └── repository/
└── shared/ # 共享模块
可视化流程图库,用于构建节点编辑器、工作流设计器。
npm install reactflow
基础用法:
import ReactFlow from 'reactflow'
import 'reactflow/dist/style.css'
const nodes = [
{ id: '1', position: { x: 0, y: 0 }, data: { label: '节点1' } },
{ id: '2', position: { x: 0, y: 100 }, data: { label: '节点2' } },
]
const edges = [{ id: 'e1-2', source: '1', target: '2' }]
function Flow() {
return (
<div style={{ height: '500px' }}>
<ReactFlow nodes={nodes} edges={edges} />
</div>
)
}
| 复杂度 | 名称 | 示例算法 | n=100 时的操作次数 | 性能评价 |
|---|---|---|---|---|
| O(1) | 常数 | 数组访问、哈希表查找 | 1 | ⚡ 最优 |
| O(log n) | 对数 | 二分查找 | 7 | ✅ 优秀 |
| O(n) | 线性 | 数组遍历 | 100 | ✅ 良好 |
| O(n log n) | 线性对数 | 快速排序、归并排序 | 664 | 🟡 可接受 |
| O(n²) | 平方 | 冒泡排序、双层循环 | 10,000 | ⚠️ 较差 |
| O(n³) | 立方 | 三层循环 | 1,000,000 | 🔴 差 |
| O(2ⁿ) | 指数 | 递归斐波那契 | 1.27×10³⁰ | 🔴 极差 |
// O(1) - 常数时间
function getFirst(arr) {
return arr[0]
}
// O(n) - 线性时间
function findMax(arr) {
let max = arr[0]
for (let i = 1; i < arr.length; i++) {
if (arr[i] > max) max = arr[i]
}
return max
}
// O(n²) - 平方时间
function bubbleSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
;[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
}
return arr
}
// O(log n) - 对数时间
function binarySearch(arr, target) {
let left = 0,
right = arr.length - 1
while (left <= right) {
const mid = Math.floor((left + right) / 2)
if (arr[mid] === target) return mid
if (arr[mid] < target) left = mid + 1
else right = mid - 1
}
return -1
}
| 数据结构 | 查找 | 插入 | 删除 | 空间 | 适用场景 |
|---|---|---|---|---|---|
| 数组 | O(1) | O(n) | O(n) | O(n) | 固定大小、随机访问 |
| 链表 | O(n) | O(1) | O(1) | O(n) | 频繁插入删除 |
| 栈 | O(n) | O(1) | O(1) | O(n) | 后进先出(LIFO) |
| 队列 | O(n) | O(1) | O(1) | O(n) | 先进先出(FIFO) |
| 哈希表 | O(1) | O(1) | O(1) | O(n) | 快速查找 |
| 二叉搜索树 | O(log n) | O(log n) | O(log n) | O(n) | 有序数据、范围查找 |
| 堆 | O(1) | O(log n) | O(log n) | O(n) | 优先队列、Top K |
class Stack {
constructor() {
this.items = []
}
// 入栈
push(element) {
this.items.push(element)
}
// 出栈
pop() {
return this.items.pop()
}
// 查看栈顶
peek() {
return this.items[this.items.length - 1]
}
// 是否为空
isEmpty() {
return this.items.length === 0
}
// 栈大小
size() {
return this.items.length
}
}
// 应用:括号匹配
function isValidParentheses(s) {
const stack = new Stack()
const map = { ')': '(', '}': '{', ']': '[' }
for (let char of s) {
if (char === '(' || char === '{' || char === '[') {
stack.push(char)
} else {
if (stack.isEmpty() || stack.pop() !== map[char]) {
return false
}
}
}
return stack.isEmpty()
}
console.log(isValidParentheses('()[]{}')) // true
console.log(isValidParentheses('([)]')) // false
class Queue {
constructor() {
this.items = []
}
// 入队
enqueue(element) {
this.items.push(element)
}
// 出队
dequeue() {
return this.items.shift()
}
// 查看队首
front() {
return this.items[0]
}
isEmpty() {
return this.items.length === 0
}
size() {
return this.items.length
}
}
// 应用:BFS 广度优先搜索
function bfs(graph, start) {
const queue = new Queue()
const visited = new Set()
const result = []
queue.enqueue(start)
visited.add(start)
while (!queue.isEmpty()) {
const node = queue.dequeue()
result.push(node)
for (let neighbor of graph[node]) {
if (!visited.has(neighbor)) {
visited.add(neighbor)
queue.enqueue(neighbor)
}
}
}
return result
}
class ListNode {
constructor(val) {
this.val = val
this.next = null
}
}
class LinkedList {
constructor() {
this.head = null
this.size = 0
}
// 添加节点
append(val) {
const newNode = new ListNode(val)
if (!this.head) {
this.head = newNode
} else {
let current = this.head
while (current.next) {
current = current.next
}
current.next = newNode
}
this.size++
}
// 插入节点
insertAt(val, index) {
if (index < 0 || index > this.size) return false
const newNode = new ListNode(val)
if (index === 0) {
newNode.next = this.head
this.head = newNode
} else {
let current = this.head
let prev = null
let i = 0
while (i < index) {
prev = current
current = current.next
i++
}
newNode.next = current
prev.next = newNode
}
this.size++
return true
}
// 删除节点
removeAt(index) {
if (index < 0 || index >= this.size) return null
let current = this.head
if (index === 0) {
this.head = current.next
} else {
let prev = null
let i = 0
while (i < index) {
prev = current
current = current.next
i++
}
prev.next = current.next
}
this.size--
return current.val
}
}
// LeetCode 经典题:反转链表
function reverseList(head) {
let prev = null
let current = head
while (current) {
const next = current.next
current.next = prev
prev = current
current = next
}
return prev
}
class TreeNode {
constructor(val) {
this.val = val
this.left = null
this.right = null
}
}
class BinaryTree {
constructor() {
this.root = null
}
// 前序遍历:根 → 左 → 右
preorderTraversal(node = this.root, result = []) {
if (node) {
result.push(node.val)
this.preorderTraversal(node.left, result)
this.preorderTraversal(node.right, result)
}
return result
}
// 中序遍历:左 → 根 → 右
inorderTraversal(node = this.root, result = []) {
if (node) {
this.inorderTraversal(node.left, result)
result.push(node.val)
this.inorderTraversal(node.right, result)
}
return result
}
// 后序遍历:左 → 右 → 根
postorderTraversal(node = this.root, result = []) {
if (node) {
this.postorderTraversal(node.left, result)
this.postorderTraversal(node.right, result)
result.push(node.val)
}
return result
}
// 层序遍历(BFS)
levelOrderTraversal() {
if (!this.root) return []
const result = []
const queue = [this.root]
while (queue.length > 0) {
const levelSize = queue.length
const currentLevel = []
for (let i = 0; i < levelSize; i++) {
const node = queue.shift()
currentLevel.push(node.val)
if (node.left) queue.push(node.left)
if (node.right) queue.push(node.right)
}
result.push(currentLevel)
}
return result
}
// 树的最大深度
maxDepth(node = this.root) {
if (!node) return 0
return 1 + Math.max(this.maxDepth(node.left), this.maxDepth(node.right))
}
}
class HashTable {
constructor(size = 53) {
this.keyMap = new Array(size)
}
// 哈希函数
_hash(key) {
let total = 0
const PRIME = 31
for (let i = 0; i < Math.min(key.length, 100); i++) {
const char = key[i]
const value = char.charCodeAt(0) - 96
total = (total * PRIME + value) % this.keyMap.length
}
return total
}
// 设置键值对
set(key, value) {
const index = this._hash(key)
if (!this.keyMap[index]) {
this.keyMap[index] = []
}
// 处理冲突:链地址法
this.keyMap[index].push([key, value])
}
// 获取值
get(key) {
const index = this._hash(key)
const bucket = this.keyMap[index]
if (bucket) {
for (let pair of bucket) {
if (pair[0] === key) {
return pair[1]
}
}
}
return undefined
}
// 删除键值对
delete(key) {
const index = this._hash(key)
const bucket = this.keyMap[index]
if (bucket) {
for (let i = 0; i < bucket.length; i++) {
if (bucket[i][0] === key) {
bucket.splice(i, 1)
return true
}
}
}
return false
}
}
// 应用:两数之和
function twoSum(nums, target) {
const map = new Map()
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i]
if (map.has(complement)) {
return [map.get(complement), i]
}
map.set(nums[i], i)
}
return []
}
console.log(twoSum([2, 7, 11, 15], 9)) // [0, 1]
| 算法 | 平均时间 | 最坏时间 | 空间 | 稳定性 | 适用场景 |
|---|---|---|---|---|---|
| 冒泡排序 | O(n²) | O(n²) | O(1) | ✅ 稳定 | 教学、小数据 |
| 选择排序 | O(n²) | O(n²) | O(1) | ❌ 不稳定 | 小数据 |
| 插入排序 | O(n²) | O(n²) | O(1) | ✅ 稳定 | 小数据、近乎有序 |
| 快速排序 | O(n log n) | O(n²) | O(log n) | ❌ 不稳定 | 通用首选 |
| 归并排序 | O(n log n) | O(n log n) | O(n) | ✅ 稳定 | 需要稳定排序 |
| 堆排序 | O(n log n) | O(n log n) | O(1) | ❌ 不稳定 | 不需要稳定性 |
function quickSort(arr, left = 0, right = arr.length - 1) {
if (left < right) {
const pivotIndex = partition(arr, left, right)
quickSort(arr, left, pivotIndex - 1)
quickSort(arr, pivotIndex + 1, right)
}
return arr
}
function partition(arr, left, right) {
const pivot = arr[right]
let i = left - 1
for (let j = left; j < right; j++) {
if (arr[j] < pivot) {
i++
;[arr[i], arr[j]] = [arr[j], arr[i]]
}
}
;[arr[i + 1], arr[right]] = [arr[right], arr[i + 1]]
return i + 1
}
console.log(quickSort([3, 6, 8, 10, 1, 2, 1])) // [1, 1, 2, 3, 6, 8, 10]
function mergeSort(arr) {
if (arr.length <= 1) return arr
const mid = Math.floor(arr.length / 2)
const left = mergeSort(arr.slice(0, mid))
const right = mergeSort(arr.slice(mid))
return merge(left, right)
}
function merge(left, right) {
const result = []
let i = 0,
j = 0
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
result.push(left[i++])
} else {
result.push(right[j++])
}
}
return result.concat(left.slice(i)).concat(right.slice(j))
}
console.log(mergeSort([3, 6, 8, 10, 1, 2, 1])) // [1, 1, 2, 3, 6, 8, 10]
核心思想:将复杂问题分解为子问题,保存子问题的解避免重复计算。
经典问题:斐波那契数列
// ❌ 暴力递归:O(2ⁿ) - 极慢
function fibRecursive(n) {
if (n <= 1) return n
return fibRecursive(n - 1) + fibRecursive(n - 2)
}
// ✅ 动态规划(自底向上):O(n) - 快
function fibDP(n) {
if (n <= 1) return n
const dp = [0, 1]
for (let i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2]
}
return dp[n]
}
// ✅ 动态规划(空间优化):O(n) 时间,O(1) 空间
function fibOptimized(n) {
if (n <= 1) return n
let prev = 0,
curr = 1
for (let i = 2; i <= n; i++) {
;[prev, curr] = [curr, prev + curr]
}
return curr
}
console.log(fibDP(10)) // 55
console.log(fibOptimized(50)) // 12586269025
经典问题:爬楼梯
// 每次可以爬 1 或 2 个台阶,求爬到第 n 阶有多少种方法
function climbStairs(n) {
if (n <= 2) return n
let prev = 1,
curr = 2
for (let i = 3; i <= n; i++) {
;[prev, curr] = [curr, prev + curr]
}
return curr
}
console.log(climbStairs(5)) // 8
经典问题:最长公共子序列(LCS)
function longestCommonSubsequence(text1, text2) {
const m = text1.length,
n = text2.length
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0))
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (text1[i - 1] === text2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])
}
}
}
return dp[m][n]
}
console.log(longestCommonSubsequence('abcde', 'ace')) // 3
核心思想:每一步选择当前最优解,期望得到全局最优解。
经典问题:买卖股票的最佳时机
function maxProfit(prices) {
let minPrice = Infinity
let maxProfit = 0
for (let price of prices) {
minPrice = Math.min(minPrice, price)
maxProfit = Math.max(maxProfit, price - minPrice)
}
return maxProfit
}
console.log(maxProfit([7, 1, 5, 3, 6, 4])) // 5 (在第2天买入,第5天卖出)
核心思想:尝试所有可能的解,遇到不满足条件的就回退。
经典问题:全排列
function permute(nums) {
const result = []
function backtrack(path, used) {
if (path.length === nums.length) {
result.push([...path])
return
}
for (let i = 0; i < nums.length; i++) {
if (used[i]) continue
path.push(nums[i])
used[i] = true
backtrack(path, used)
path.pop()
used[i] = false
}
}
backtrack([], [])
return result
}
console.log(permute([1, 2, 3]))
// [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]
经典问题:N 皇后
function solveNQueens(n) {
const result = []
const board = Array.from({ length: n }, () => Array(n).fill('.'))
function isValid(row, col) {
// 检查列
for (let i = 0; i < row; i++) {
if (board[i][col] === 'Q') return false
}
// 检查左上对角线
for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] === 'Q') return false
}
// 检查右上对角线
for (let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (board[i][j] === 'Q') return false
}
return true
}
function backtrack(row) {
if (row === n) {
result.push(board.map((row) => row.join('')))
return
}
for (let col = 0; col < n; col++) {
if (!isValid(row, col)) continue
board[row][col] = 'Q'
backtrack(row + 1)
board[row][col] = '.'
}
}
backtrack(0)
return result
}
console.log(solveNQueens(4).length) // 2 种解法
function debounce(func, delay) {
let timer = null
return function (...args) {
clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, delay)
}
}
// 应用:搜索输入框
const searchInput = document.getElementById('search')
const debouncedSearch = debounce((value) => {
console.log('搜索:', value)
// 发送 API 请求
}, 300)
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value)
})
function throttle(func, delay) {
let lastTime = 0
return function (...args) {
const now = Date.now()
if (now - lastTime >= delay) {
func.apply(this, args)
lastTime = now
}
}
}
// 应用:页面滚动
const throttledScroll = throttle(() => {
console.log('滚动位置:', window.scrollY)
}, 200)
window.addEventListener('scroll', throttledScroll)
class LRUCache {
constructor(capacity) {
this.capacity = capacity
this.cache = new Map()
}
get(key) {
if (!this.cache.has(key)) return -1
// 更新为最近使用
const value = this.cache.get(key)
this.cache.delete(key)
this.cache.set(key, value)
return value
}
put(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key)
}
this.cache.set(key, value)
// 超出容量,删除最久未使用的
if (this.cache.size > this.capacity) {
const firstKey = this.cache.keys().next().value
this.cache.delete(firstKey)
}
}
}
// 应用:HTTP 缓存
const cache = new LRUCache(3)
cache.put('page1', 'data1')
cache.put('page2', 'data2')
cache.put('page3', 'data3')
cache.put('page4', 'data4') // 'page1' 被淘汰
console.log(cache.get('page1')) // -1
function deepClone(obj, hash = new WeakMap()) {
// 处理 null 和基本类型
if (obj === null || typeof obj !== 'object') return obj
// 处理日期
if (obj instanceof Date) return new Date(obj)
// 处理正则
if (obj instanceof RegExp) return new RegExp(obj)
// 处理循环引用
if (hash.has(obj)) return hash.get(obj)
// 处理数组
if (Array.isArray(obj)) {
const arrCopy = []
hash.set(obj, arrCopy)
obj.forEach((item, index) => {
arrCopy[index] = deepClone(item, hash)
})
return arrCopy
}
// 处理对象
const objCopy = {}
hash.set(obj, objCopy)
Object.keys(obj).forEach((key) => {
objCopy[key] = deepClone(obj[key], hash)
})
return objCopy
}
// 测试
const obj = { a: 1, b: { c: 2 } }
obj.self = obj // 循环引用
const cloned = deepClone(obj)
console.log(cloned.b === obj.b) // false
// 方法1:递归
function flatten(arr) {
const result = []
arr.forEach((item) => {
if (Array.isArray(item)) {
result.push(...flatten(item))
} else {
result.push(item)
}
})
return result
}
// 方法2:使用 reduce
function flattenReduce(arr) {
return arr.reduce((acc, item) => {
return acc.concat(Array.isArray(item) ? flattenReduce(item) : item)
}, [])
}
// 方法3:指定深度
function flattenDepth(arr, depth = 1) {
if (depth === 0) return arr
return arr.reduce((acc, item) => {
return acc.concat(Array.isArray(item) ? flattenDepth(item, depth - 1) : item)
}, [])
}
console.log(flatten([1, [2, [3, [4]]]])) // [1, 2, 3, 4]
console.log(flattenDepth([1, [2, [3, [4]]]], 2)) // [1, 2, 3, [4]]
1. 两数之和(Two Sum)
function twoSum(nums, target) {
const map = new Map()
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i]
if (map.has(complement)) {
return [map.get(complement), i]
}
map.set(nums[i], i)
}
return []
}
2. 三数之和(3Sum)
function threeSum(nums) {
const result = []
nums.sort((a, b) => a - b)
for (let i = 0; i < nums.length - 2; i++) {
if (i > 0 && nums[i] === nums[i - 1]) continue
let left = i + 1
let right = nums.length - 1
while (left < right) {
const sum = nums[i] + nums[left] + nums[right]
if (sum === 0) {
result.push([nums[i], nums[left], nums[right]])
while (left < right && nums[left] === nums[left + 1]) left++
while (left < right && nums[right] === nums[right - 1]) right--
left++
right--
} else if (sum < 0) {
left++
} else {
right--
}
}
}
return result
}
1. 最长回文子串(Longest Palindromic Substring)
function longestPalindrome(s) {
if (s.length < 2) return s
let start = 0
let maxLen = 1
function expandAroundCenter(left, right) {
while (left >= 0 && right < s.length && s[left] === s[right]) {
if (right - left + 1 > maxLen) {
start = left
maxLen = right - left + 1
}
left--
right++
}
}
for (let i = 0; i < s.length; i++) {
expandAroundCenter(i, i) // 奇数长度
expandAroundCenter(i, i + 1) // 偶数长度
}
return s.substring(start, start + maxLen)
}
1. 合并两个有序链表(Merge Two Sorted Lists)
function mergeTwoLists(l1, l2) {
const dummy = new ListNode(0)
let current = dummy
while (l1 && l2) {
if (l1.val < l2.val) {
current.next = l1
l1 = l1.next
} else {
current.next = l2
l2 = l2.next
}
current = current.next
}
current.next = l1 || l2
return dummy.next
}
1. 二叉树的最近公共祖先(Lowest Common Ancestor)
function lowestCommonAncestor(root, p, q) {
if (!root || root === p || root === q) return root
const left = lowestCommonAncestor(root.left, p, q)
const right = lowestCommonAncestor(root.right, p, q)
if (left && right) return root
return left || right
}
前端技术体系涵盖:
构建工具:Webpack / Vite 配置与优化核心技术:Node / Web API / React 深度应用安全性能:XSS / CSRF 防御、渲染优化设计模式:单例、观察者、发布订阅架构原则:SOLID、分层、微前端、DDD数据结构与算法:栈、队列、树、图、排序、动态规划核心理念:高内聚、低耦合、可维护、可扩展