JavaScript
轻量级、解释型、面向对象的脚本语言 —— Web 前端核心语言
官网:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
简介
JavaScript(简称 JS)是一种动态类型、弱类型、基于原型的脚本语言,与 HTML 和 CSS 并称为 Web 三大核心技术。
语言特性
| 特性 | 说明 |
|---|---|
| 动态类型 | 变量类型在运行时确定,无需声明类型 |
| 弱类型 | 不同类型可自动隐式转换 |
| 原型继承 | 对象直接继承其他对象(而非类继承) |
| 一等函数 | 函数是一等公民,可作为参数/返回值/赋值 |
| 事件驱动 | 基于事件循环的异步非阻塞模型 |
| 跨平台 | 浏览器、服务器(Node.js)、移动端、桌面端 |
JavaScript 引擎
| 引擎 | 开发商 | 运行环境 |
|---|---|---|
| V8 | Chrome、Node.js、Deno、Electron | |
| SpiderMonkey | Mozilla | Firefox |
| JavaScriptCore | Apple | Safari、Bun |
| Chakra | Microsoft | 旧版 Edge(已弃用) |
发展时间线
1995 Brendan Eich 创立 JavaScript(10 天完成原型)
1997 ECMAScript 1 标准发布
2009 ES5 发布(严格模式、JSON、数组方法)
2015 ES6 / ES2015 发布(let/const、箭头函数、类、模块)
2016 ES2016(Array.includes、指数运算符)
2017 ES2017(async/await、Object.values、字符串填充)
2018 ES2018(扩展运算符对象、Promise.finally)
2019 ES2019(Array.flat、Object.fromEntries)
2020 ES2020(可选链 ?.、空值合并 ??、BigInt、globalThis)
2021 ES2021(String.replaceAll、Promise.any、逻辑赋值)
2022 ES2022(类静态块、正则 d 标志、Error cause)
2023 ES2023(Array.findLast、Hashbang 语法、Symbols 作为 WeakMap 键)
2024 ES2024(正则 v 标志、Promise.withResolvers、Atomics.waitAsync)开发工具
代码编辑器
| 工具 | 特点 |
|---|---|
| VSCode | 微软出品,插件丰富,前端开发首选 |
| WebStorm | JetBrains 出品,专业前端 IDE |
| Sublime Text | 轻量快速,适合快速编辑 |
| Vim / Neovim | 终端编辑器,高效键盘操作 |
包管理工具
bash
npm install lodash # 安装包
npm install -g serve # 全局安装
npm uninstall lodash # 卸载
npm update # 更新所有包
npm ls # 查看已安装包
# yarn(Facebook 出品,替代 npm)
yarn add lodash
yarn remove lodash
# pnpm(高性能,节省磁盘空间)
pnpm add lodash构建工具
| 工具 | 说明 | 适用场景 |
|---|---|---|
| Webpack | 老牌打包工具,配置灵活 | 大型项目,复杂配置 |
| Vite | 基于 ES Module 的下一代构建工具 | 推荐新项目使用 |
| esbuild | Go 编写,速度极快的打包器 | 库构建,高性能场景 |
| Rollup | Tree Shaking 优秀的库打包器 | 发布 NPM 库 |
| Parcel | 零配置打包工具 | 快速原型 |
代码质量
bash
# ESLint — 代码检查
npm install -D eslint
npx eslint src/
# Prettier — 代码格式化
npm install -D prettier
npx prettier --write src/
# TypeScript — 类型检查
npm install -D typescript
npx tsc --noEmit调试工具
- Chrome DevTools — 浏览器内置调试器,断点/Network/Performance
- React DevTools — React 组件调试
- Vue DevTools — Vue 组件调试
- vscode-debugger — VSCode 集成调试
常见框架与库
前端框架
| 框架 | 特点 | 适用场景 |
|---|---|---|
| React | Facebook 出品,虚拟 DOM,组件化 | 大型单页应用,跨平台 |
| Vue | 渐进式框架,上手简单,模板语法 | 中小型项目到大型应用 |
| Angular | Google 出品,大而全,TypeScript 原生 | 企业级应用 |
| Svelte | 编译时框架,无虚拟 DOM,体积小 | 高性能场景 |
| Solid | 细粒度响应式,性能接近原生 JS | 追求极致的性能场景 |
| Alpine.js | 轻量,类似 Vue/Tailwind 风格的 HTML 增强 | 简单交互页面 |
状态管理
| 库 | 说明 | 配套框架 |
|---|---|---|
| Redux | 可预测状态容器 | React |
| Zustand | 轻量状态管理 | React |
| Pinia | Vue 官方状态管理 | Vue |
| MobX | 响应式状态管理 | React |
| Jotai | 原子化状态管理 | React |
| Valtio | 代理式状态管理 | React |
| Recoil | Facebook 出品原子化状态(实验性) | React |
UI 组件库
| 库 | 说明 |
|---|---|
| Ant Design (antd) | 企业级 UI 设计语言,React 生态 |
| Element Plus | Vue 3 组件库 |
| Naive UI | Vue 3 组件库,TypeScript 原生 |
| Shadcn/ui | 现代化 React 组件,可定制 |
| Tailwind CSS | 原子化 CSS 框架 |
| Bootstrap | 经典 CSS 框架 |
工具库
| 库 | 说明 |
|---|---|
| Lodash | 实用工具函数集合 |
| Day.js | 轻量日期库(2KB 替代 Moment.js) |
| Axios | HTTP 请求库(浏览器 + Node.js) |
| Zod | 运行时类型校验库 |
| TanStack Query | 服务端状态管理,缓存,请求 |
| SWR | 数据获取(stale-while-revalidate) |
| Prisma | 数据库 ORM(Node.js) |
| Drizzle ORM | 轻量 TypeScript ORM |
| Playwright | 浏览器自动化测试 |
| Vitest | Vite 生态单元测试框架 |
| Cypress | 前端端到端测试 |
运行时环境
Node.js
Node.js 将 JavaScript 带到服务端,基于 V8 引擎和事件循环。
| 版本 | 时间 | 里程碑 |
|---|---|---|
| Node.js 0.12 | 2015 | 稳定版,npm 生态起步 |
| Node.js 4.0 | 2015 | 合并 io.js,长期支持 |
| Node.js 8.0 | 2017 | async/await 原生支持 |
| Node.js 14.0 | 2020 | ES Module 稳定支持 |
| Node.js 18.0 | 2022 | 内置测试运行器 |
| Node.js 22.0 | 2024 | WebSocket 内置,ESM 增强 |
Deno
Ryan Dahl(Node.js 原作者)开发的 JavaScript/TypeScript 安全运行时:
- 原生 TypeScript — 无需配置即可运行
- 安全 — 默认无文件/网络权限
- 去中心化 — 支持 URL 导入
Bun
Node.js 的高性能替代品:
- 速度 — JavaScriptCore 引擎,启动和运行比 Node.js 快 4 倍
- 内置工具 — 打包器、转译器、包管理器一体
- 兼容 — 兼容大部分 Node.js API
应用场景
Web 前端
JavaScript 的核心领域,构建浏览器端交互界面。
服务端(Node.js)
- Web API 服务(Express / Koa / Fastify / Hono)
- 实时通信(WebSocket / Socket.IO)
- 微服务网关
- 中间层代理(BFF)
跨平台桌面应用
| 框架 | 说明 |
|---|---|
| Electron | 用 JS/CSS/HTML 构建桌面应用(VSCode、Slack、Discord) |
| Tauri | Rust 后端 + Web 前端,体积小性能好 |
| NW.js | 类似 Electron,更早的桌面方案 |
移动端
| 框架 | 说明 |
|---|---|
| React Native | 用 React 构建原生移动应用 |
| Flutter | Dart 语言,高性能跨平台 |
| Capacitor | Web 应用打包为移动 App |
| Expo | React Native 的简化开发工具 |
云函数与边缘计算
- Cloudflare Workers — 边缘计算,无服务器
- AWS Lambda — 云函数(支持 Node.js)
- Vercel Edge Functions — 边缘函数
- Deno Deploy — 分布式无服务器平台
命令行工具
Node.js 打造的 CLI 工具:
bash
# 常用 CLI 工具
npm install -g create-react-app # React 脚手架
npm install -g vue-cli # Vue 脚手架
npm install -g serve # 静态文件服务器
npm install -g pm2 # 进程管理器
npm install -g typescript # TypeScript 编译器游戏开发
| 引擎/框架 | 说明 |
|---|---|
| Phaser | 2D 游戏引擎,PixiJS 渲染 |
| Three.js | 3D 图形库 |
| Babylon.js | 3D 游戏引擎 |
| Cocos Creator | 2D/3D 跨平台游戏引擎 |
| PixiJS | 2D 渲染引擎 |
JavaScript 的优缺点
优势
- 浏览器原生 — 无需安装,打开即用
- 全栈覆盖 — 前后端、桌面、移动端都用同一语言
- 事件驱动异步 — 非阻塞 I/O,高并发场景优秀
- 生态第一 — npm 全球最大包管理器,200 万+包
- 社区活跃 — 框架迭代快,学习资源丰富
- TypeScript — 可选类型系统,大型项目更可靠
劣势
- 动态类型 — 大型项目容易出运行时错误(TypeScript 可弥补)
- 单线程 — CPU 密集型任务不占优势(Worker 线程可部分缓解)
- 回调历史 — 遗留代码可能有回调地狱
- 工具链碎片 — 框架/构建工具选型繁多,决策成本高
- 浏览器兼容 — 旧浏览器不支持新特性(Babel 转译)
- 浮点精度 —
0.1 + 0.2 !== 0.3
基础语法
变量声明
javascript
// var(函数作用域,不推荐)
var x = 1
// let(块级作用域)
let y = 2
// const(不可重新赋值,引用可修改)
const z = 3
const arr = [1, 2, 3]
arr.push(4) // 合法
// 变量提升(hoisting)
console.log(a) // undefined(不是 ReferenceError)
var a = 1
console.log(b) // ReferenceError
let b = 2数据类型
javascript
// 原始类型(7 种)
typeof undefined // "undefined"
typeof true // "boolean"
typeof 42 // "number"
typeof 'hello' // "string"
typeof 9007199254740991n // "bigint"
typeof Symbol('id') // "symbol"
typeof null // "object"(历史遗留 bug)
// 对象类型
typeof {} // "object"
typeof [] // "object"
typeof function(){} // "function"
typeof new Date() // "object"类型转换
javascript
// 显式转换
Number('42') // 42
String(42) // '42'
Boolean(0) // false
parseInt('42px') // 42
parseFloat('3.14') // 3.14
// 隐式转换(避免)
'5' - 2 // 3(字符串转数字)
'5' + 2 // '52'(数字转字符串,+ 优先字符串拼接)
!'hello' // false(非空字符串转 true)
!!0 // false
// 假值(falsy values)
// false, 0, ''(空字符串), null, undefined, NaN运算符
javascript
// 算术
+ - * / % ** // ** 指数运算符(ES2016)
// 比较
== === // == 会类型转换,=== 严格比较(推荐 ===)
!= !==
// 逻辑
&& || !
// 逻辑赋值(ES2021)
let a = null
a ??= 'default' // 空值赋值:a 为 null/undefined 时赋值
let b = 1
b &&= 2 // b 为 truthy 时赋值
let c = 0
c ||= 3 // c 为 falsy 时赋值
// 可选链(ES2020)
const city = user?.address?.city // 避免 TypeError
// 空值合并(ES2020)
const name = user.name ?? '匿名' // 只有 null/undefined 才取默认值字符串
javascript
// 字符串方法
'hello'.length // 5
'hello'.toUpperCase() // 'HELLO'
'hello'.includes('ll') // true
'hello'.startsWith('he') // true
'hello'.slice(0, 2) // 'he'
' hi '.trim() // 'hi'
'hello world'.split(' ') // ['hello', 'world']
'abc'.repeat(3) // 'abcabc'
// 模板字符串(ES6)
const name = 'Alice'
const age = 30
console.log(`姓名: ${name}, 年龄: ${age}`)
// 多行字符串
const html = `
<div>
<p>Hello</p>
</div>`数组
javascript
const arr = [1, 2, 3, 4, 5]
arr.push(6) // 末尾添加
arr.pop() // 末尾删除
arr.unshift(0) // 开头添加
arr.shift() // 开头删除
arr.slice(0, 2) // [1, 2](不修改原数组)
arr.splice(1, 2) // 从索引 1 删除 2 个元素(修改原数组)
arr.indexOf(3) // 2
arr.includes(3) // true(ES2016)
arr.find(x => x > 3) // 4(返回第一个匹配的元素)
arr.findIndex(x => x > 3) // 3(返回第一个匹配的索引)
arr.findLast(x => x > 3) // 5(ES2023,从后往前找)
arr.concat([6, 7]) // [1,2,3,4,5,6,7]
arr.join(',') // '1,2,3,4,5'
arr.flat() // 展开嵌套数组(ES2019)
// 扩展运算符
const copy = [...arr]
const merged = [...arr, 6, 7]
// 解构赋值
const [first, second, ...rest] = arr对象
javascript
// 创建对象
const user = {
name: 'Alice',
age: 30,
greet() { // 简写方法
console.log(`Hi, I'm ${this.name}`)
},
get info() { // getter
return `${this.name}, ${this.age}`
},
set info(val) { // setter
this.name = val
}
}
// 属性访问
user.name // 'Alice'
user['age'] // 30
// 删除属性
delete user.age
// 属性检查
'name' in user // true
user.hasOwnProperty('name') // true
// 对象方法
Object.keys(user) // ['name', 'age']
Object.values(user) // ['Alice', 30]
Object.entries(user) // [['name','Alice'], ['age',30]]
Object.fromEntries(entries) // 二维数组转对象(ES2019)
Object.assign({}, user) // 浅拷贝
const copy2 = {...user} // 扩展运算符浅拷贝
// 属性简写(ES6)
const name = 'Alice', age = 30
const obj = { name, age } // { name: 'Alice', age: 30 }
// 计算属性名(ES6)
const key = 'dynamic'
const obj2 = { [key]: 'value' }函数
函数定义
javascript
// 函数声明(提升)
function add(a, b) {
return a + b
}
// 函数表达式(不提升)
const multiply = function(a, b) {
return a * b
}
// 箭头函数(ES6,不绑定 this)
const subtract = (a, b) => a - b
const greet = name => `Hello ${name}`
const noArgs = () => 'no params'
// 箭头函数与 this
const obj = {
name: 'Alice',
regularFunc: function() { console.log(this.name) }, // 指向 obj
arrowFunc: () => console.log(this.name) // 指向外层(window/undefined)
}参数处理
javascript
// 默认参数
function greet(name = '匿名', prefix = '你好') {
return `${prefix}, ${name}`
}
// 剩余参数
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0)
}
// 参数解构
function createUser({ name, age = 18 }) {
return `${name} 今年 ${age} 岁`
}
// arguments(箭头函数不可用)
function logArgs() {
console.log(arguments)
// 转数组
const args = Array.from(arguments)
const args2 = [...arguments]
}闭包
javascript
function createCounter() {
let count = 0 // 私有变量
return function() { // 闭包
return ++count
}
}
const counter = createCounter()
counter() // 1
counter() // 2
counter() // 3
// 实际应用:防抖
function debounce(fn, delay) {
let timer = null
return function(...args) {
clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, args), delay)
}
}高阶函数
javascript
const arr = [1, 2, 3, 4, 5]
// map — 映射
arr.map(x => x * 2) // [2, 4, 6, 8, 10]
// filter — 过滤
arr.filter(x => x > 2) // [3, 4, 5]
// reduce — 归约
arr.reduce((acc, x) => acc + x, 0) // 15
arr.reduce((acc, x) => acc * x, 1) // 120
// forEach — 遍历
arr.forEach(x => console.log(x))
// some / every
arr.some(x => x > 4) // true(有一个满足即可)
arr.every(x => x > 0) // true(全部满足)
// sort
arr.sort((a, b) => a - b) // 升序
arr.sort((a, b) => b - a) // 降序
// 链式调用
arr.filter(x => x % 2 === 0)
.map(x => x * 10)
.reduce((a, b) => a + b)Promise 与异步
回调 → Promise → async/await 演进
javascript
// 回调地狱
getUser(1, (user) => {
getPosts(user.id, (posts) => {
getComments(posts[0].id, (comments) => {
console.log(comments)
})
})
})
// Promise 链式
getUser(1)
.then(user => getPosts(user.id))
.then(posts => getComments(posts[0].id))
.then(comments => console.log(comments))
.catch(err => console.error(err))
// async/await(ES2017)
async function loadComments() {
try {
const user = await getUser(1)
const posts = await getPosts(user.id)
const comments = await getComments(posts[0].id)
console.log(comments)
} catch (err) {
console.error(err)
}
}创建 Promise
javascript
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true
if (success) {
resolve('成功数据')
} else {
reject(new Error('失败'))
}
}, 1000)
})Promise 静态方法
javascript
// 并行执行
Promise.all([p1, p2, p3]) // 全部成功才 resolve,一个失败就 reject
Promise.allSettled([p1, p2, p3]) // 所有 Promise 完成后返回(ES2020)
Promise.race([p1, p2, p3]) // 第一个完成的 Promise(无论成功/失败)
Promise.any([p1, p2, p3]) // 第一个成功的 Promise(ES2021)
Promise.resolve('value') // 创建一个 resolve 的 Promise
Promise.reject(new Error('err')) // 创建一个 reject 的 Promise异步迭代
javascript
// for-await-of(ES2018)
async function process(items) {
const results = []
for await (const item of asyncGenerator(items)) {
results.push(item)
}
return results
}定时器
javascript
setTimeout(() => {}, 1000) // 一次性
setInterval(() => {}, 1000) // 周期性
setImmediate(() => {}) // Node.js 微任务
requestAnimationFrame(() => {}) // 浏览器下一帧
// 清除
const timer = setTimeout(() => {}, 1000)
clearTimeout(timer)类与面向对象
ES6 类
javascript
class Animal {
// 静态属性(ES2022)
static kingdom = 'Animalia'
// 私有属性(ES2022,# 语法)
#secret = 'hidden'
constructor(name) {
this.name = name // 公有属性
this.#init()
}
// 私有方法(ES2022)
#init() {
console.log('初始化完成')
}
// 实例方法
speak() {
console.log(`${this.name} 发出了声音`)
}
// 静态方法
static create(name) {
return new Animal(name)
}
// getter / setter
get secret() {
return this.#secret
}
}
// 继承
class Dog extends Animal {
constructor(name) {
super(name) // 必须调用 super
this.breed = '狗'
}
speak() { // 重写
console.log(`${this.name}: 汪汪!`)
}
get owner() {
return super.secret // 访问父类 getter
}
}原型链
javascript
// 构造函数
function Person(name) {
this.name = name
}
// 原型方法
Person.prototype.greet = function() {
return `Hi, I'm ${this.name}`
}
const p = new Person('Alice')
p.greet() // 'Hi, I'm Alice'
p.__proto__ === Person.prototype // true
Person.prototype.__proto__ === Object.prototype // true
// instanceof
p instanceof Person // true
p instanceof Object // true模块
JavaScript 的模块化经历了从社区方案到语言原生支持的演进过程。
模块系统演进
无模块(全局变量) → IIFE → CommonJS → AMD → UMD → ES Module(官方标准)
1995───────────── 2009─── 2011── 2014── 2015─────────────→模块格式对比
| 特性 | CommonJS | AMD / RequireJS | UMD | ES Module |
|---|---|---|---|---|
| 运行环境 | Node.js | 浏览器(运行时) | 通用 | 浏览器 + Node.js |
| 加载方式 | 同步 | 异步 | 自动判断 | 异步(静态分析) |
| 语法 | require() / module.exports | define() / require() | 兼容 CJS + AMD | import / export |
| 静态分析 | ❌ | ❌ | ❌ | ✅(Tree Shaking 基础) |
| 循环依赖 | 支持(返回 partial) | 支持 | 视情况 | 支持 |
| 动态导入 | ✅ 原生支持 | ✅ | ✅ | ✅(import()) |
| 浏览器原生 | ❌ 需要打包 | ❌ 需要加载器 | ❌ 需要打包 | ✅(type="module") |
IIFE(自执行函数)—— 最原始的模块化
javascript
// 利用函数作用域隔离变量
const MyModule = (function() {
// 私有变量
let count = 0
// 私有函数
function log(msg) {
console.log(msg)
}
// 公开 API
return {
increment() {
count++
log(`count: ${count}`)
},
getCount() {
return count
}
}
})()
MyModule.increment() // count: 1
MyModule.count // undefined(私有,无法直接访问)CommonJS
Node.js 采用的模块标准,同步加载,适合服务端。
javascript
// ──── 导出 ────
// 方式一:exports.xxx
exports.hello = function() {
return 'Hello World'
}
// 方式二:module.exports(推荐,覆盖前者)
module.exports = {
hello() {
return 'Hello World'
}
}
// 方式三:导出单个值
module.exports = class Calculator {}
// ──── 导入 ────
const math = require('./math')
const { PI, add } = require('./math')
const Calculator = require('./calculator')
// ──── 特点 ────
// 1. 同步加载(I/O 密集型场景无影响)
// 2. 首次加载后缓存(重复 require 返回同一实例)
// 3. 支持动态路径
const mod = require(isProd ? './prod' : './dev')
// 4. 循环依赖时返回已执行部分的 exports循环依赖示例:
javascript
// a.js
console.log('a 开始执行')
exports.done = false
const b = require('./b')
console.log('a 中引用 b.done:', b.done)
exports.done = true
console.log('a 执行完毕')
// b.js
console.log('b 开始执行')
exports.done = false
const a = require('./a') // a 只执行到一半
console.log('b 中引用 a.done:', a.done) // false(尚未执行到 exports.done = true)
exports.done = true
console.log('b 执行完毕')
// main.js
const a = require('./a')
const b = require('./b')
// 输出:
// a 开始执行
// b 开始执行
// b 中引用 a.done: false
// b 执行完毕
// a 中引用 b.done: true
// a 执行完毕AMD / RequireJS
异步模块定义(Asynchronous Module Definition),专为浏览器异步加载设计。
javascript
// ──── 定义模块 ────
// define(id?, dependencies?, factory)
// 无依赖模块
define('math', function() {
return {
add: function(a, b) { return a + b }
}
})
// 有依赖模块
define('calculator', ['math', 'logger'], function(math, logger) {
return {
sum: function(arr) {
const result = arr.reduce((a, b) => math.add(a, b), 0)
logger.log(`计算结果: ${result}`)
return result
}
}
})
// ──── 加载模块 ────
require(['calculator', 'jquery'], function(calc, $) {
console.log(calc.sum([1, 2, 3]))
})
// ──── 兼容 CommonJS 写法 ────
define(function(require, exports, module) {
const math = require('./math')
exports.sum = function(arr) {
return arr.reduce((a, b) => math.add(a, b), 0)
}
})AMD vs CommonJS 核心区别:
| 对比 | CommonJS | AMD |
|---|---|---|
| 加载时机 | 运行时同步加载 | 运行时异步加载 |
| 设计目标 | 服务端 | 浏览器 |
| 依赖声明 | 执行到 require 时才知道 | define 时提前声明 |
| 浏览器直接使用 | ❌ 需打包 | ✅ 需 RequireJS 加载器 |
| 当前状态 | Node.js 默认(逐步迁移 ESM) | 已被打包工具取代 |
UMD(通用模块定义)
UMD 是一套兼容模式,同时支持 CommonJS、AMD 和全局变量三种环境。
javascript
// ──── 典型 UMD 模板 ────
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD 环境(RequireJS)
define(['jquery'], factory)
} else if (typeof module === 'object' && module.exports) {
// CommonJS 环境(Node.js)
module.exports = factory(require('jquery'))
} else {
// 浏览器全局变量
root.MyLib = factory(root.jQuery)
}
})(this, function($) {
// 实际模块代码
return {
greet: function(name) {
return `Hello ${name}`
}
}
})特点:
- 一套代码在三种环境下都能运行
- 代码冗余(每次都要包裹判断逻辑)
- 过渡方案,ES Module 普及后逐渐淡出
ES Module(官方标准)
ES6 引入的语言原生模块系统,目前是 JavaScript 模块的最终标准。
javascript
// ──── 导出 ────
// math.js
export const PI = 3.14159
export function add(a, b) { return a + b }
export class Calculator {}
// 默认导出(每个模块一个)
export default function log(msg) {
console.log(msg)
}
// 重命名导出
export { add as sum }
// 先声明后导出
const VERSION = '1.0'
export { VERSION }
// 批量重导出
export * from './utils'
export { default as Logger } from './logger'
// ──── 导入 ────
// index.js
import Calculator, { PI, add, VERSION } from './math.js'
import * as Math from './math.js' // 命名空间导入
import { add as myAdd } from './math.js' // 重命名
import './polyfill.js' // 仅执行副作用
// 动态导入(返回 Promise)
const math = await import('./math.js')
// ──── 特点 ────
// 1. 静态分析:import 必须在模块顶层,不能放在条件语句中
// 2. Tree Shaking:未使用的导出被打包工具移除
// 3. 异步加载:浏览器环境不会阻塞渲染
// 4. 严格模式:模块自动启用 'use strict'
// 5. 单例:同一模块多次导入返回同一实例
// ──── HTML 中引用 ────
// <script type="module" src="main.js"></script>
// <script type="module">
// import { add } from './math.js'
// console.log(add(1, 2))
// </script>SystemJS
一种通用模块加载器,支持所有模块格式(ESM、CJS、AMD、UMD),在浏览器端按需加载。
html
<!-- HTML 引入 -->
<script src="system.js"></script>
<script>
System.import('./app.js').then(function(module) {
module.default()
})
</script>javascript
// System.register 格式(SystemJS 编译产物)
System.register(['lodash'], function(exports) {
return {
execute: function() {
exports('default', function greet(name) {
return `Hello ${name}`
})
}
}
})场景: 微前端架构中,不同子应用使用不同模块格式时,SystemJS 可作为统一加载器。
如何选择
| 项目类型 | 推荐模块格式 | 原因 |
|---|---|---|
| 浏览器 Web 应用 | ES Module | 原生支持,Tree Shaking |
| Node.js 服务端 | CommonJS 或 ES Module | CJS 稳定兼容,ESM 是未来 |
| 新项目(2020+) | ES Module | 官方标准,工具链成熟 |
| 开源库(NPM 发布) | UMD 或 双格式 | 兼容各类使用者环境 |
| 旧项目迁移 | ES Module(逐步替换) | 打包工具(Webpack/Vite)支持混用 |
| 微前端 | SystemJS | 运行时加载,格式无关 |
迭代器与生成器
迭代器
javascript
// 可迭代对象
const iterable = {
[Symbol.iterator]() {
let step = 0
return {
next() {
step++
if (step <= 3) {
return { value: step, done: false }
}
return { done: true }
}
}
}
}
for (const item of iterable) {
console.log(item) // 1, 2, 3
}生成器
javascript
function* generateId() {
let id = 0
while (true) {
yield ++id
}
}
const gen = generateId()
gen.next().value // 1
gen.next().value // 2
// 委托 yield*
function* combine() {
yield* [1, 2, 3]
yield* 'abc'
}
[...combine()] // [1, 2, 3, 'a', 'b', 'c']Map、Set、WeakMap、WeakRef
Map
javascript
const map = new Map()
map.set('key', 'value')
map.get('key') // 'value'
map.has('key') // true
map.delete('key')
map.size // 0
// 任意类型作为键
map.set({}, 'object')
map.set(Symbol(), 'symbol')
// 与 Object 对比
// Map:有序、键任意类型、size 属性、iterable
// Object:无序、键只能是 String/Symbol、需 Object.keys() 遍历Set
javascript
const set = new Set([1, 2, 2, 3, 3, 3])
set.size // 3(自动去重)
set.has(2) // true
set.add(4)
set.delete(1)
// 数组去重
[...new Set([1, 2, 2, 3])] // [1, 2, 3]WeakMap / WeakSet
键为弱引用,不阻止垃圾回收,用于防止内存泄漏:
javascript
const wm = new WeakMap()
let obj = {}
wm.set(obj, 'some data')
obj = null // 数据被自动回收
// WeakMap 不可迭代,无 size 属性代理与反射
Proxy
javascript
const handler = {
get(target, prop, receiver) {
if (prop === 'secret') {
return '无权访问'
}
return Reflect.get(target, prop, receiver)
},
set(target, prop, value) {
if (prop === 'age' && value < 0) {
throw new Error('年龄不能为负')
}
return Reflect.set(target, prop, value)
},
has(target, prop) {
return prop in target
},
deleteProperty(target, prop) {
return delete target[prop]
}
}
const user = new Proxy({ name: 'Alice', age: 30 }, handler)
user.age = -1 // Error
user.secret // '无权访问'错误处理
javascript
// try-catch-finally
try {
const result = riskyOperation()
} catch (err) {
console.error(err.message)
console.error(err.stack)
} finally {
cleanup()
}
// 自定义错误(ES2022 支持 Error cause)
class BusinessError extends Error {
constructor(message, { cause, code }) {
super(message, { cause })
this.code = code
}
}
throw new BusinessError('余额不足', {
cause: { accountId: 123, balance: 0 },
code: 'INSUFFICIENT_FUNDS'
})严格模式
javascript
// 全局严格模式
'use strict'
// 函数级严格模式
function strictFunc() {
'use strict'
}
// 自动启用严格模式的情况:
// - ES Module(<script type="module">)
// - 类(class 内部)常用 API
数字
javascript
Number.isNaN(NaN) // true(推荐,全局 isNaN 有类型转换问题)
Number.isFinite(Infinity) // false
Number.isInteger(3.0) // true
Math.floor(3.7) // 3
Math.round(3.4) // 3
Math.ceil(3.1) // 4
Math.random() // 0~1 随机小数
Math.max(1, 2, 3) // 3
Math.min(1, 2, 3) // 1日期
javascript
const now = new Date()
new Date('2024-12-25')
new Date(2024, 11, 25) // 月从 0 开始
now.getFullYear() // 2024
now.getMonth() // 0-11
now.getDate() // 1-31
now.getDay() // 0(周日)-6(周六)
now.getHours() // 0-23
now.getTime() // 时间戳(毫秒)
now.toISOString() // '2024-12-25T10:00:00.000Z'
now.toLocaleDateString('zh-CN') // '2024/12/25'
// 日期运算
const later = new Date(now.getTime() + 86400000) // 加一天JSON
javascript
JSON.stringify({ name: 'Alice', age: undefined }) // '{"name":"Alice"}'(忽略 undefined)
JSON.parse('{"name":"Alice"}')
JSON.stringify(obj, null, 2) // 格式化为 2 空格缩进
// 自定义序列化
const user = {
name: 'Alice',
toJSON() {
return { name: this.name, type: 'user' }
}
}控制台
javascript
console.log, .warn, .error, .info
console.table([{a:1, b:2}]) // 表格输出
console.time('label') / .timeEnd // 计时
console.group('label') / .groupEnd // 分组
console.trace() // 堆栈跟踪
console.count('label') // 计数DOM 操作
javascript
// 选择元素
document.querySelector('.class') // 单个
document.querySelectorAll('.class') // NodeList
document.getElementById('id')
document.getElementsByClassName('class')
document.getElementsByTagName('div')
// 修改内容
el.textContent = '新文本' // 纯文本
el.innerHTML = '<span>HTML</span>' // HTML(注意 XSS)
// 修改属性
el.setAttribute('data-id', '123')
el.getAttribute('data-id')
el.dataset.id // '123'(dataset 快捷方式)
// CSS 类
el.classList.add('active')
el.classList.remove('active')
el.classList.toggle('active')
el.classList.contains('active')
// 样式
el.style.color = 'red'
el.style.backgroundColor = 'blue' // CSS 属性驼峰命名
getComputedStyle(el).color
// DOM 操作
document.createElement('div')
parent.appendChild(child)
parent.insertBefore(newNode, refNode)
parent.removeChild(child)
child.remove()
// 事件
el.addEventListener('click', (e) => {
e.preventDefault() // 阻止默认行为
e.stopPropagation() // 阻止冒泡
e.target // 实际触发元素
})JSONP
JSONP 是跨域请求的一种早期方案,利用 <script> 标签不受同源策略限制的特点:
javascript
// 客户端
function handleResponse(data) {
console.log('收到数据:', data)
}
const script = document.createElement('script')
script.src = 'https://api.example.com/data?callback=handleResponse'
document.head.appendChild(script)
// 服务端返回
// handleResponse({ "name": "Alice", "age": 30 })现代开发中,JSONP 已被 CORS 方案替代。
Fetch API
javascript
// GET
const res = await fetch('/api/users')
const users = await res.json()
// POST
const res = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice' })
})
// 错误处理
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`)
}浏览器环境
全局对象
javascript
// 浏览器
window // 全局对象
this === window // true(非严格模式)
document // DOM 文档
navigator // 浏览器信息 navigator.userAgent
location // URL 信息 location.href
history // 浏览历史 history.back()
localStorage // 持久化存储(5MB)
sessionStorage // 会话存储
// Node.js
global // 全局对象
process // 进程信息 process.env
globalThis // 统一方式访问全局对象(ES2020)事件循环
执行栈(Call Stack)
↓
微任务队列(Microtask Queue)
- Promise.then/catch/finally
- MutationObserver
- queueMicrotask()
↓
宏任务队列(Macrotask Queue)
- setTimeout / setInterval
- I/O
- UI 渲染
- requestAnimationFrame(特殊)javascript
console.log('1') // 同步
setTimeout(() => { // 宏任务
console.log('2')
}, 0)
Promise.resolve().then(() => { // 微任务
console.log('3')
})
queueMicrotask(() => { // 微任务
console.log('4')
})
console.log('5') // 同步
// 输出顺序:1 → 5 → 3 → 4 → 2Node.js 基础
文件系统
javascript
const fs = require('fs')
const fsPromises = require('fs/promises')
// 同步
const data = fs.readFileSync('file.txt', 'utf8')
// 回调
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) throw err
console.log(data)
})
// Promise
const data = await fsPromises.readFile('file.txt', 'utf8')
await fsPromises.writeFile('output.txt', data)路径
javascript
const path = require('path')
path.join('a', 'b', 'c') // 'a/b/c'
path.resolve('a', 'b') // 绝对路径
path.basename('/a/b/file.js') // 'file.js'
path.extname('file.js') // '.js'
path.dirname('/a/b/file.js') // '/a/b'进程与环境
javascript
console.log(process.cwd()) // 当前工作目录
console.log(process.env.NODE_ENV) // 环境变量
console.log(process.argv) // 命令行参数
console.log(process.pid) // 进程 ID
process.on('uncaughtException', (err) => {
console.error('未捕获异常:', err)
})
process.exit(0) // 正常退出
process.exit(1) // 异常退出模块系统进阶
动态导入与条件加载
javascript
// 条件加载
const module = await import(
isAdmin ? './admin.js' : './user.js'
)
// 缓存控制
const url = '/api/config?t=' + Date.now()
const module = await import(url)导入属性(Import Attributes,ES2025)
javascript
import config from './config.json' with { type: 'json' }
import('./data.json', { with: { type: 'json' } })编写可维护的代码
设计原则
- 关注点分离 — 一个函数只做一件事
- 避免副作用 — 纯函数优先,副作用集中管理
- 防御性编程 — 访问深层属性使用可选链
?. - 尽早返回 — 减少嵌套层级
- 命名清晰 — 变量/函数名自注释
常见反模式
javascript
// ❌ 全局变量
totalPrice = 100
// ✅ 模块化
let totalPrice = 100
// ❌ 深嵌套回调
getData((a) => {
getMore(a, (b) => {
getEvenMore(b, (c) => {})
})
})
// ✅ async/await
async function process() {
const a = await getData()
const b = await getMore(a)
const c = await getEvenMore(b)
}
// ❌ == 比较
if (x == '123') {}
// ✅ === 比较
if (x === '123') {}