ES6+ 现代特性
ES6(ES2015)是 JavaScript 的分水岭,此后每年发布新特性。掌握这些特性是写出现代 JS 的基础。
解构赋值
js
// 数组解构
const [a, b, ...rest] = [1, 2, 3, 4, 5]
// a=1, b=2, rest=[3,4,5]
// 跳过元素
const [,, third] = [1, 2, 3] // third=3
// 默认值
const [x = 10, y = 20] = [5] // x=5, y=20
// 对象解构
const { name, age, address: { city } } = {
name: 'Alice',
age: 30,
address: { city: 'Beijing' }
}
// 重命名 + 默认值
const { name: userName = 'Anonymous', role = 'user' } = { name: 'Bob' }
// userName='Bob', role='user'
// 函数参数解构
function render({ title, content, theme = 'light' }) {
return `<div class="${theme}"><h1>${title}</h1>${content}</div>`
}展开运算符 & 剩余参数
js
// 展开数组
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' }
const config = { ...defaults, theme: 'dark', debug: true }
// { theme: 'dark', lang: 'zh', debug: true }
// 剩余参数
function sum(first, ...rest) {
return rest.reduce((acc, n) => acc + n, first)
}
sum(1, 2, 3, 4) // 10
// 克隆数组/对象(浅拷贝)
const clone = [...original]
const objClone = { ...original }模板字符串
js
const name = 'World'
const multiline = `
Hello, ${name}!
Today is ${new Date().toLocaleDateString()}
2 + 2 = ${2 + 2}
`
// 标签模板(Tagged Template)
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
const value = values[i - 1]
return result + (value ? `<mark>${value}</mark>` : '') + str
})
}
const keyword = 'JavaScript'
highlight`学习 ${keyword} 很有趣`
// '学习 <mark>JavaScript</mark> 很有趣'
// 实际应用:SQL 防注入
function sql(strings, ...values) {
const sanitized = values.map(v => escape(v))
return strings.reduce((q, s, i) => q + (sanitized[i-1] ?? '') + s)
}可选链 & 空值合并(ES2020)
js
const user = {
profile: {
address: null
}
}
// ❌ 老写法:繁琐
const city = user && user.profile && user.profile.address && user.profile.address.city
// ✅ 可选链
const city = user?.profile?.address?.city // undefined(不报错)
// 方法调用
user?.profile?.getAvatar?.()
// 数组访问
const first = arr?.[0]
// 空值合并:只有 null/undefined 才用默认值(区别于 ||)
const port = config.port ?? 3000 // config.port 为 0 时,用 0 而非 3000
const name = user.name || 'Guest' // user.name 为 '' 时,用 'Guest'(可能不是你想要的)
const name2 = user.name ?? 'Guest' // user.name 为 '' 时,用 ''
// 赋值简写(ES2021)
user.name ??= 'Anonymous' // 只有 null/undefined 时才赋值
user.count ||= 0 // falsy 时赋值
user.count &&= user.count + 1 // truthy 时赋值Symbol
js
// Symbol 是唯一的原始值
const id1 = Symbol('id')
const id2 = Symbol('id')
console.log(id1 === id2) // false
// 用作对象的唯一键(不会与其他属性冲突)
const ID = Symbol('id')
const user = {
[ID]: 123,
name: 'Alice'
}
console.log(user[ID]) // 123
// Symbol 键不会出现在 for...in 和 Object.keys() 中
// 内置 Symbol(Well-known Symbols)
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance)
}
}
console.log([] instanceof MyArray) // true
// 自定义迭代器
class Range {
constructor(start, end) {
this.start = start
this.end = end
}
[Symbol.iterator]() {
let current = this.start
const end = this.end
return {
next() {
return current <= end
? { value: current++, done: false }
: { done: true }
}
}
}
}
for (const n of new Range(1, 5)) {
console.log(n) // 1 2 3 4 5
}Map & Set
js
// Map:键可以是任意类型
const map = new Map()
const keyObj = { id: 1 }
map.set(keyObj, 'Alice')
map.set('name', 'Bob')
map.set(42, 'Charlie')
map.get(keyObj) // 'Alice'
map.size // 3
// 遍历
for (const [key, value] of map) {
console.log(key, value)
}
// 对象转 Map
const obj = { a: 1, b: 2 }
const mapFromObj = new Map(Object.entries(obj))
// Set:唯一值集合
const set = new Set([1, 2, 3, 2, 1])
console.log([...set]) // [1, 2, 3]
// 数组去重
const unique = [...new Set(arr)]
// 集合运算
const a = new Set([1, 2, 3, 4])
const b = new Set([3, 4, 5, 6])
const union = new Set([...a, ...b]) // 并集
const intersection = new Set([...a].filter(x => b.has(x))) // 交集
const difference = new Set([...a].filter(x => !b.has(x))) // 差集常用 ES2022+ 特性
js
// Array.at():支持负索引
const arr = [1, 2, 3, 4, 5]
arr.at(-1) // 5(最后一个)
arr.at(-2) // 4
// Object.hasOwn():替代 hasOwnProperty
Object.hasOwn(obj, 'key') // 更安全,不受原型链影响
// Error cause(ES2022)
try {
await fetchData()
} catch (err) {
throw new Error('数据加载失败', { cause: err })
}
// Array.findLast / findLastIndex(ES2023)
const last = arr.findLast(x => x % 2 === 0)
// Object.groupBy(ES2024)
const people = [
{ name: 'Alice', dept: 'Engineering' },
{ name: 'Bob', dept: 'Marketing' },
{ name: 'Carol', dept: 'Engineering' },
]
const byDept = Object.groupBy(people, p => p.dept)
// { Engineering: [...], Marketing: [...] }总结
- 解构 + 展开运算符让数据操作更简洁
- 可选链
?.和空值合并??是处理 null/undefined 的利器 Map/Set在需要非字符串键或唯一值时优于普通对象/数组Symbol用于创建唯一标识符和自定义对象行为- 每年跟进 ECMAScript 新特性,善用 MDN 查兼容性