JavaScript ES6+ 语法
大约 12 分钟约 3572 字
JavaScript ES6+ 语法
简介
ES6(ECMAScript 2015)是 JavaScript 语言的重大升级,引入了 let/const、箭头函数、解构赋值、模板字符串、Promise、模块化等现代语法。后续版本(ES7-ES13)持续增加了 async/await、可选链、空值合并等实用特性。掌握 ES6+ 是现代前端开发的必备基础。
ES 版本演进时间线:
- ES5 (2009):严格模式、JSON 支持、Array 方法
- ES6/ES2015 (2015):let/const、箭头函数、Promise、class、模块化、解构
- ES7/ES2016 (2016):指数运算符 **、Array.includes
- ES8/ES2017 (2017):async/await、Object.values/entries、String padding
- ES9/ES2018 (2018):展开运算符、Promise.finally、async 迭代器
- ES10/ES2019 (2019):Array.flat/flatMap、Object.fromEntries
- ES11/ES2020 (2020):可选链 ?.、空值合并 ??、BigInt、动态 import
- ES12/ES2021 (2021):Promise.any、String.replaceAll、逻辑赋值
- ES13/ES2022 (2022):类字段、私有方法、Array.at()、顶层 await
- ES14/ES2023 (2023):Array.fromAsync、Hashbang 语法
特点
变量与函数
let/const 和箭头函数
// let 和 const
const API_URL = 'https://api.example.com'; // 常量
let count = 0; // 可变变量
// var 已不推荐使用
// 箭头函数
const add = (a, b) => a + b;
const greet = name => `Hello, ${name}!`;
const log = (...args) => console.log(...args);
// 对比传统函数
// function add(a, b) { return a + b; }
// 箭头函数中的 this(继承外层)
const team = {
name: '开发组',
members: ['Alice', 'Bob', 'Charlie'],
showMembers() {
this.members.forEach(member => {
console.log(`${member} 属于 ${this.name}`);
// this 正确指向 team 对象
});
}
};
// 默认参数
const createUser = (name, role = 'viewer', active = true) => ({
name, role, active
});
// Rest 参数
const sum = (...numbers) => numbers.reduce((acc, n) => acc + n, 0);
sum(1, 2, 3, 4, 5); // 15var/let/const 的区别
// var vs let vs const 的关键区别
// 1. 作用域
// var: 函数作用域(function scope)
// let/const: 块级作用域(block scope)
if (true) {
var x = 1; // 函数作用域,if 外部也能访问
let y = 2; // 块级作用域,if 外部无法访问
const z = 3; // 块级作用域,if 外部无法访问
}
console.log(x); // 1
// console.log(y); // ReferenceError
// console.log(z); // ReferenceError
// 2. 变量提升
// var: 变量声明提升(hoisting),值为 undefined
// let/const: 存在"暂时性死区"(TDZ),声明前访问报错
console.log(a); // undefined(var 提升)
// console.log(b); // ReferenceError(TDZ)
var a = 1;
let b = 2;
// 3. 重复声明
var x = 1;
var x = 2; // 允许
let y = 1;
// let y = 2; // SyntaxError: 不允许重复声明
// 4. 全局对象属性
// var: 在全局作用域中会挂载到 window 上
// let/const: 不会挂载到 window 上
var globalVar = 'hello';
let globalLet = 'world';
console.log(window.globalVar); // 'hello'
console.log(window.globalLet); // undefined
// 经典面试题:for 循环中的 var vs let
// ❌ 使用 var —— 所有回调共享同一个 i
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// 输出: 3, 3, 3
// ✅ 使用 let —— 每次循环创建新的 i
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// 输出: 0, 1, 2解构与展开
解构赋值
// 对象解构
const user = { name: '张三', age: 25, email: 'zhang@test.com', role: 'admin' };
const { name, age, email, role = 'viewer' } = user;
// 重命名
const { name: userName, age: userAge } = user;
// 数组解构
const colors = ['red', 'green', 'blue', 'yellow'];
const [first, second, ...rest] = colors;
// first = 'red', second = 'green', rest = ['blue', 'yellow']
// 函数参数解构
const renderUser = ({ name, age, email }) => {
console.log(`${name} (${age}) - ${email}`);
};
// 交换变量
let a = 1, b = 2;
[a, b] = [b, a];
// 展开运算符
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const merged = [...arr1, ...arr2]; // [1,2,3,4,5,6]
const defaults = { theme: 'light', lang: 'zh', pageSize: 20 };
const userPrefs = { theme: 'dark', pageSize: 50 };
const finalPrefs = { ...defaults, ...userPrefs };
// { theme: 'dark', lang: 'zh', pageSize: 50 }解构赋值高级用法
// 嵌套解构
const response = {
data: {
user: {
name: '张三',
address: { city: '北京', district: '海淀' }
}
}
}
const { data: { user: { name, address: { city } } } } = response
// 解构时设置默认值(深度嵌套)
const config = {
api: { baseUrl: 'https://api.example.com' }
}
const {
api: {
baseUrl,
timeout = 5000,
retry: { count = 3, delay = 1000 } = {}
}
} = config
// 数组解构跳过元素
const [first, , third] = [1, 2, 3] // first=1, third=3
// 函数返回值解构
function getMinMax(arr) {
return { min: Math.min(...arr), max: Math.max(...arr) }
}
const { min, max } = getMinMax([3, 1, 4, 1, 5])
// React/Vue 中常用的解构模式
// props 解构
function Button({ label, onClick, disabled = false, variant = 'primary' }) {
return { label, onClick, disabled, variant }
}
// 状态解构
const [state, setState] = useState({ count: 0, name: '' })
const { count, name } = state模板字符串与字符串方法
字符串处理
// 模板字符串
const name = '张三';
const age = 25;
const intro = `我是${name},今年${age}岁`;
const multiLine = `
第一行
第二行
第三行
`;
// 标签模板
const highlight = (strings, ...values) => {
return strings.reduce((result, str, i) => {
const value = values[i] ? `<strong>${values[i]}</strong>` : '';
return result + str + value;
}, '');
};
const output = highlight`用户 ${name} 的年龄是 ${age}`;
// "用户 <strong>张三</strong> 的年龄是 <strong>25</strong>"
// ES6+ 字符串方法
'test'.startsWith('te'); // true
'test'.endsWith('st'); // true
'test'.includes('es'); // true
'abc'.repeat(3); // 'abcabcabc'
'hello'.padStart(10, '.'); // '.....hello'
'hello'.padEnd(10, '.'); // 'hello.....'Promise 与 async/await
异步编程
// Promise 基础
const fetchUser = (id) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) {
resolve({ id, name: '张三' });
} else {
reject(new Error('无效的用户 ID'));
}
}, 1000);
});
};
// async/await
const loadUserData = async (userId) => {
try {
const user = await fetchUser(userId);
console.log(user.name);
return user;
} catch (error) {
console.error('加载失败:', error.message);
return null;
}
};
// 并行请求
const loadDashboard = async () => {
const [users, orders, stats] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/orders').then(r => r.json()),
fetch('/api/stats').then(r => r.json())
]);
return { users, orders, stats };
};
// Promise.allSettled — 等待所有完成(不论成败)
const results = await Promise.allSettled([
fetchUser(1),
fetchUser(2),
fetchUser(-1) // 这个会失败
]);
// results[2].status === 'rejected'Promise 进阶模式
// Promise 静态方法对比
// Promise.all:全部成功才成功,一个失败就失败
// Promise.allSettled:等待所有完成,不论成败
// Promise.race:第一个完成(不论成败)的结果
// Promise.any:第一个成功的结果
// Promise.race —— 超时控制
function fetchWithTimeout(url, timeout = 5000) {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('请求超时')), timeout)
),
])
}
// Promise.allSettled —— 并行请求,全部完成后统一处理
const results = await Promise.allSettled([
fetchUser(1),
fetchUser(2),
fetchUser(3),
])
const succeeded = results.filter(r => r.status === 'fulfilled').map(r => r.value)
const failed = results.filter(r => r.status === 'rejected').map(r => r.reason)
// Promise.any —— 只要有一个成功就行
const fastest = await Promise.any([
fetch('https://api1.example.com/data'),
fetch('https://api2.example.com/data'),
fetch('https://api3.example.com/data'),
])
// 顺序执行异步任务(非并行)
async function runSequentially(tasks) {
const results = []
for (const task of tasks) {
const result = await task()
results.push(result)
}
return results
}
// 并发控制(限制同时执行的 Promise 数量)
async function asyncPool(limit, items, fn) {
const executing = new Set()
for (const item of items) {
const promise = fn(item).then(() => executing.delete(promise))
executing.add(promise)
if (executing.size >= limit) {
await Promise.race(executing)
}
}
return Promise.all(executing)
}
// 使用:最多 3 个并发请求
await asyncPool(3, urls, url => fetch(url).then(r => r.json()))async/await 错误处理模式
// 模式 1:try/catch(基础)
async function loadData() {
try {
const res = await fetch('/api/data')
const data = await res.json()
return data
} catch (error) {
console.error('请求失败:', error)
return null
}
}
// 模式 2:封装错误处理工具函数
function withErrorHandling(fn) {
return async (...args) => {
try {
return [await fn(...args), null]
} catch (error) {
return [null, error]
}
}
}
// 使用
const [data, error] = await withErrorHandling(() => fetchUser(1))
if (error) {
console.error('加载用户失败:', error)
} else {
console.log(data)
}
// 模式 3:并行请求中的错误处理
async function loadWithFallback(urls) {
for (const url of urls) {
try {
const res = await fetch(url)
if (res.ok) return await res.json()
} catch {
continue // 尝试下一个 URL
}
}
throw new Error('所有请求都失败了')
}
// await 在顶层使用(ES2022)
// 只能在 ES Module 中使用
// const data = await fetch('/api/data')类与模块
面向对象
// class 类
class EventEmitter {
#listeners = new Map(); // 私有字段
on(event, callback) {
if (!this.#listeners.has(event)) {
this.#listeners.set(event, []);
}
this.#listeners.get(event).push(callback);
return this;
}
emit(event, ...args) {
const callbacks = this.#listeners.get(event) || [];
callbacks.forEach(cb => cb(...args));
}
off(event, callback) {
const callbacks = this.#listeners.get(event) || [];
const index = callbacks.indexOf(callback);
if (index > -1) callbacks.splice(index, 1);
}
}
// 继承
class TypedEventEmitter extends EventEmitter {
emit(event, data) {
console.log(`[${event}]`, data);
super.emit(event, data);
}
}
// ES 模块
// math.js
export const add = (a, b) => a + b;
export const multiply = (a, b) => a * b;
export default class Calculator { /* ... */ }
// app.js
import Calculator, { add, multiply } from './math.js';ES2020-ES2023 新特性
可选链与空值合并
// 可选链操作符 ?.
const user = { address: { city: '北京' } }
user?.name // undefined(不会报错)
user?.address?.city // '北京'
user?.address?.zip?.code // undefined
document?.querySelector('.btn')?.click()
// 数组可选链
const arr = null
arr?.[0] // undefined
// 函数可选链
const fn = null
fn?.() // undefined
// 空值合并运算符 ??
const value = null ?? '默认值' // '默认值'
const value2 = 0 ?? '默认值' // 0(只有 null/undefined 才触发)
const value3 = '' ?? '默认值' // ''(空字符串不触发)
const value4 = false ?? '默认值' // false(不触发)
// 对比 || 运算符
// || 是"假值"合并(0, '', false, NaN 都会被替换)
// ?? 只合并 null 和 undefined
const port = process.env.PORT || 3000 // 如果 PORT='0',结果是 3000(可能不符合预期)
const port2 = process.env.PORT ?? 3000 // 如果 PORT='0',结果是 '0'(正确)其他现代特性
// Array.at() —— 支持负索引
const arr = [1, 2, 3, 4, 5]
arr.at(-1) // 5(最后一个元素)
arr.at(-2) // 4
// 等价于 arr[arr.length - 1],但更简洁
// Array.flat() / flatMap()
const nested = [1, [2, 3], [4, [5, 6]]]
nested.flat() // [1, 2, 3, 4, [5, 6]](默认展开一层)
nested.flat(2) // [1, 2, 3, 4, 5, 6](展开两层)
nested.flat(Infinity) // [1, 2, 3, 4, 5, 6](全部展开)
const pairs = [[1, 2], [3, 4], [5, 6]]
pairs.flatMap(([a, b]) => [a + b, a * b]) // [3, 2, 7, 12, 11, 30]
// Object.fromEntries()
const entries = [['name', '张三'], ['age', 25]]
const obj = Object.fromEntries(entries) // { name: '张三', age: 25 }
// Map 和 Set
const map = new Map()
map.set('key', 'value')
map.get('key') // 'value'
map.has('key') // true
map.size // 1
const set = new Set([1, 2, 3, 2, 1]) // Set {1, 2, 3}
set.add(4)
set.has(3) // true
set.size // 4
[...new Set([1, 2, 2, 3])] // [1, 2, 3](数组去重)
// BigInt —— 大整数
const big = 9007199254740991n
const big2 = BigInt('9007199254740991')
big + 1n // 9007199254740992n
// 逻辑赋值运算符
let x = null
x ||= 'default' // x = 'default'(仅当 x 为假值时赋值)
x &&= 'updated' // x = 'updated'(仅当 x 为真值时赋值)
x ??= 'fallback' // x = 'updated'(仅当 x 为 null/undefined 时赋值)
// 动态 import()
const module = await import('./heavy-module.js')
module.doSomething()
// globalThis —— 统一的全局对象
// 浏览器中:window === globalThis
// Node.js 中:global === globalThis
// Web Worker 中:self === globalThis常用设计模式
// 1. 观察者模式(发布-订阅)
class EventBus {
#events = new Map()
on(event, handler) {
const handlers = this.#events.get(event) || []
handlers.push(handler)
this.#events.set(event, handlers)
return () => this.off(event, handler)
}
off(event, handler) {
const handlers = this.#events.get(event) || []
this.#events.set(event, handlers.filter(h => h !== handler))
}
emit(event, ...args) {
const handlers = this.#events.get(event) || []
handlers.forEach(h => h(...args))
}
once(event, handler) {
const wrapper = (...args) => {
handler(...args)
this.off(event, wrapper)
}
this.on(event, wrapper)
}
}
// 2. 工厂模式
function createUser(type, config) {
switch (type) {
case 'admin':
return { ...config, role: 'admin', permissions: ['all'] }
case 'editor':
return { ...config, role: 'editor', permissions: ['read', 'write'] }
default:
return { ...config, role: 'viewer', permissions: ['read'] }
}
}
// 3. 策略模式
const validationStrategies = {
required: (value) => value ? null : '此字段为必填项',
minLength: (value, min) => value.length >= min ? null : `最少 ${min} 个字符`,
email: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) ? null : '邮箱格式不正确',
}
function validate(value, rules) {
for (const rule of rules) {
const error = validationStrategies[rule.type]?.(value, rule.param)
if (error) return error
}
return null
}
// 4. 单例模式
class Database {
static #instance = null
static getInstance() {
if (!Database.#instance) {
Database.#instance = new Database()
}
return Database.#instance
}
}优点
缺点
总结
ES6+ 是现代 JavaScript 的基础。核心语法:let/const 替代 var,箭头函数简化代码,解构赋值提取数据,模板字符串拼接文本。异步编程统一使用 async/await。模块化使用 import/export。建议所有新项目使用 ES6+ 语法,配合 TypeScript 获得更好的类型安全。
开发规范建议:
- 优先使用 const,只在需要重新赋值时使用 let,永远不使用 var
- 优先使用箭头函数(回调、简短逻辑),类方法使用普通函数
- 优先使用解构赋值替代对象属性逐一提取
- 异步代码统一使用 async/await,避免 .then 链式调用
- 使用 ?? 替代 ||(避免 0/''/false 被误替换)
- 使用 ?. 替代繁琐的 && 短路判断
关键知识点
- 先判断主题更偏浏览器原理、框架机制、工程化还是性能优化。
- 前端问题很多看似是页面问题,实际源头在构建、缓存、状态流或接口协作。
- 真正成熟的前端方案一定同时考虑首屏、交互、可维护性和线上诊断。
- 前端主题最好同时看浏览器原理、框架机制和工程化约束。
项目落地视角
- 把组件边界、状态归属、网络层规范和错误处理先定下来。
- 上线前检查包体积、缓存命中、接口失败路径和关键交互降级策略。
- 如果主题和性能有关,最好用 DevTools、Lighthouse 或埋点验证。
- 对关键页面先建立状态流和数据流,再考虑组件拆分。
常见误区
- 只盯框架 API,不理解浏览器和运行时成本。
- 把状态、请求和 UI 更新混成一层,后期难维护。
- 线上问题出现时没有日志、埋点和性能基线可对照。
- 只追框架新特性,不分析实际渲染成本。
进阶路线
- 继续补齐 SSR、边缘渲染、设计系统和监控告警能力。
- 把主题和后端接口约定、CI/CD、缓存策略一起思考。
- 沉淀组件规范、页面模板和性能基线,减少团队差异。
- 继续补齐设计系统、SSR/边缘渲染、监控告警和组件库治理。
适用场景
- 当你准备把《JavaScript ES6+ 语法》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合中后台应用、门户站点、组件库和实时交互页面。
- 当需求涉及状态流、路由、网络缓存、SSR/CSR 或性能治理时,这类主题很关键。
落地建议
- 先定义组件边界和状态归属,再落地 UI 细节。
- 对核心页面做首屏、体积、缓存和错误路径检查。
- 把安全、兼容性和可访问性纳入默认交付标准。
排错清单
- 先用浏览器 DevTools 看请求、性能面板和控制台错误。
- 检查依赖版本、构建配置、环境变量和静态资源路径。
- 如果是线上问题,优先确认缓存、CDN 和构建产物是否一致。
复盘问题
- 如果把《JavaScript ES6+ 语法》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《JavaScript ES6+ 语法》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《JavaScript ES6+ 语法》最大的收益和代价分别是什么?
