Skip to content

ES6 及 ES6+ 新特性详解

概述

ECMAScript 是 JavaScript 的标准规范。ES6(ECMAScript 2015)是一次重大更新,引入了大量新特性。此后,ECMA 国际组织决定每年发布一个新版本,统称为 ES6+ 或 ES.Next。


一、ES6 (ES2015) 新特性

ES6 是 JavaScript 历史上最重要的更新之一,引入了许多现代 JavaScript 开发的核心特性。

1. let 和 const 声明

javascript
// let - 块级作用域,可重新赋值
let name = 'Alice'
name = 'Bob' // 允许

// const - 块级作用域,常量,不可重新赋值
const PI = 3.14159
// PI = 3.14; // TypeError

// 块级作用域示例
if (true) {
  let blockScoped = 'only in this block'
  var functionScoped = 'function scoped'
}
console.log(functionScoped) // 'function scoped'
// console.log(blockScoped); // ReferenceError

// 暂时性死区 (Temporal Dead Zone)
console.log(x) // undefined (var 提升)
var x = 10

// console.log(y); // ReferenceError (TDZ)
let y = 20

特点:

  • letconst 具有块级作用域
  • 不存在变量提升(存在暂时性死区)
  • 不允许重复声明
  • const 声明的引用类型可以修改属性,但不能重新赋值

2. 箭头函数 (Arrow Functions)

javascript
// 基本语法
const add = (a, b) => a + b
const square = x => x * x
const greet = () => 'Hello!'

// 带函数体的写法
const sum = (a, b) => {
  const result = a + b
  return result
}

// 返回对象字面量需要加括号
const createUser = (name, age) => ({ name, age })

// this 绑定特性
const obj = {
  name: 'Alice',
  // 普通函数:this 取决于调用方式
  greetRegular: function () {
    console.log(this.name)
  },
  // 箭头函数:this 继承自外层作用域
  greetArrow: () => {
    console.log(this.name) // undefined (继承外层 this)
  },
  // 正确用法
  greetCorrect: function () {
    const arrow = () => console.log(this.name)
    arrow() // 'Alice'
  }
}

特点:

  • 更简洁的语法
  • 没有自己的 this,继承外层作用域的 this
  • 没有 arguments 对象
  • 不能用作构造函数(不能使用 new
  • 没有 prototype 属性

3. 模板字符串 (Template Literals)

javascript
const name = 'Alice'
const age = 25

// 基本用法
const greeting = `Hello, ${name}! You are ${age} years old.`

// 多行字符串
const html = `
<div class="card">
    <h2>${name}</h2>
    <p>Age: ${age}</p>
</div>
`

// 标签模板 (Tagged Templates)
function highlight(strings, ...values) {
  return strings.reduce((result, str, i) => {
    const value = values[i] ? `<mark>${values[i]}</mark>` : ''
    return result + str + value
  }, '')
}

const result = highlight`Hello ${name}, you are ${age}`
// "Hello <mark>Alice</mark>, you are <mark>25</mark>"

// 原始字符串
const raw = String.raw`Line 1\nLine 2` // 包含实际的 \n 字符

4. 解构赋值 (Destructuring)

javascript
// 数组解构
const [first, second, ...rest] = [1, 2, 3, 4, 5]
console.log(first) // 1
console.log(rest) // [3, 4, 5]

// 默认值
const [a = 10, b = 20] = [5]
console.log(a, b) // 5, 20

// 交换变量
let x = 1,
  y = 2
;[x, y] = [y, x]

// 对象解构
const person = { name: 'Alice', age: 25, city: 'NYC' }
const { name, age, country = 'USA' } = person

// 重命名
const { name: userName, age: userAge } = person

// 嵌套解构
const company = {
  name: 'Tech Corp',
  address: {
    city: 'San Francisco',
    country: 'USA'
  }
}
const {
  address: { city }
} = company

// 函数参数解构
function printUser({ name, age }) {
  console.log(`${name} is ${age} years old`)
}
printUser(person)

// 函数参数默认值 + 解构
function createUser({ name = 'Anonymous', age = 0 } = {}) {
  return { name, age }
}

5. 展开运算符和剩余参数 (Spread & Rest)

javascript
// 展开运算符 (Spread) - 数组
const arr1 = [1, 2, 3]
const arr2 = [...arr1, 4, 5] // [1, 2, 3, 4, 5]
const arr3 = [0, ...arr1] // [0, 1, 2, 3]

// 数组复制(浅拷贝)
const copy = [...arr1]

// 合并数组
const merged = [...arr1, ...arr2]

// 展开运算符 - 对象
const obj1 = { a: 1, b: 2 }
const obj2 = { c: 3, ...obj1 } // { c: 3, a: 1, b: 2 }
const obj3 = { ...obj1, b: 3 } // { a: 1, b: 3 } (后者覆盖)

// 函数调用时展开
const numbers = [1, 2, 3]
Math.max(...numbers) // 3

// 剩余参数 (Rest)
function sum(...args) {
  return args.reduce((total, n) => total + n, 0)
}
sum(1, 2, 3, 4) // 10

// 结合解构
const [first, ...others] = [1, 2, 3, 4]
const { a, ...remaining } = { a: 1, b: 2, c: 3 }

6. 默认参数 (Default Parameters)

javascript
// 基本用法
function greet(name = 'World') {
  return `Hello, ${name}!`
}
greet() // 'Hello, World!'
greet('Alice') // 'Hello, Alice!'

// 表达式作为默认值
function add(a, b = a * 2) {
  return a + b
}
add(5) // 15 (5 + 10)

// 函数作为默认值
function getDefault() {
  return 'default value'
}
function test(value = getDefault()) {
  console.log(value)
}

// 必填参数模式
function required(paramName) {
  throw new Error(`Parameter ${paramName} is required`)
}
function createUser(name = required('name')) {
  return { name }
}

7. 类 (Classes)

javascript
// 类声明
class Person {
  // 构造函数
  constructor(name, age) {
    this.name = name
    this.age = age
  }

  // 实例方法
  greet() {
    console.log(`Hello, I'm ${this.name}`)
  }

  // Getter
  get info() {
    return `${this.name}, ${this.age} years old`
  }

  // Setter
  set age(value) {
    if (value > 0) {
      this._age = value
    }
  }

  // 静态方法
  static createAnonymous() {
    return new Person('Anonymous', 0)
  }

  // 静态属性 (ES2022 正式支持)
  static species = 'Homo sapiens'
}

// 继承
class Employee extends Person {
  constructor(name, age, position) {
    super(name, age) // 必须先调用 super
    this.position = position
  }

  // 重写父类方法
  greet() {
    super.greet() // 调用父类方法
    console.log(`I work as a ${this.position}`)
  }
}

// 类表达式
const Animal = class {
  constructor(name) {
    this.name = name
  }
}

8. 模块化 (Modules)

javascript
// ========== math.js ==========
// 命名导出
export const PI = 3.14159;
export function add(a, b) {
    return a + b;
}
export class Calculator {
    // ...
}

// 默认导出(每个模块只能有一个)
export default class MathUtils {
    static square(x) {
        return x * x;
    }
}

// ========== main.js ==========
// 命名导入
import { PI, add, Calculator } from './math.js';

// 默认导入
import MathUtils from './math.js';

// 混合导入
import MathUtils, { PI, add } from './math.js';

// 全部导入
import * as MathModule from './math.js';
MathModule.add(1, 2);

// 重命名导入
import { add as sum } from './math.js';

// 动态导入 (ES2020)
async function loadModule() {
    const module = await import('./math.js');
    module.add(1, 2);
}

// 重新导出
export { add, PI } from './math.js';
export * from './utils.js';
export { default } from './math.js';

9. Promise

javascript
// 创建 Promise
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = true
    if (success) {
      resolve('Operation succeeded')
    } else {
      reject(new Error('Operation failed'))
    }
  }, 1000)
})

// 使用 Promise
promise
  .then(result => {
    console.log(result)
    return 'Next step'
  })
  .then(nextResult => {
    console.log(nextResult)
  })
  .catch(error => {
    console.error(error)
  })
  .finally(() => {
    console.log('Cleanup')
  })

// Promise 静态方法
const p1 = Promise.resolve('immediate value')
const p2 = Promise.reject('error')

// Promise.all - 所有成功才成功
Promise.all([promise1, promise2, promise3])
  .then(results => console.log(results))
  .catch(error => console.error(error))

// Promise.race - 返回最先完成的结果
Promise.race([promise1, promise2]).then(result => console.log(result))

// 封装回调为 Promise
function promisify(fn) {
  return function (...args) {
    return new Promise((resolve, reject) => {
      fn(...args, (err, result) => {
        if (err) reject(err)
        else resolve(result)
      })
    })
  }
}

10. 迭代器与生成器 (Iterators & Generators)

javascript
// 迭代器协议
const iterator = {
  data: [1, 2, 3],
  index: 0,
  [Symbol.iterator]() {
    return {
      next: () => {
        if (this.index < this.data.length) {
          return { value: this.data[this.index++], done: false }
        }
        return { done: true }
      }
    }
  }
}

// 生成器函数
function* numberGenerator() {
  yield 1
  yield 2
  yield 3
}

const gen = numberGenerator()
console.log(gen.next()) // { value: 1, done: false }
console.log(gen.next()) // { value: 2, done: false }
console.log(gen.next()) // { value: 3, done: false }
console.log(gen.next()) // { value: undefined, done: true }

// 无限序列
function* infiniteSequence() {
  let i = 0
  while (true) {
    yield i++
  }
}

// yield* 委托给另一个生成器
function* generator1() {
  yield 1
  yield 2
}
function* generator2() {
  yield* generator1()
  yield 3
}

// 生成器作为可迭代对象
function* range(start, end) {
  for (let i = start; i <= end; i++) {
    yield i
  }
}
for (const num of range(1, 5)) {
  console.log(num)
}

// 异步生成器 (ES2018)
async function* asyncGenerator() {
  const data = await fetch('/api/data')
  yield data.json()
}

11. for...of 循环

javascript
// 遍历数组
const arr = ['a', 'b', 'c']
for (const item of arr) {
  console.log(item)
}

// 遍历字符串
for (const char of 'Hello') {
  console.log(char)
}

// 遍历 Map
const map = new Map([
  ['a', 1],
  ['b', 2]
])
for (const [key, value] of map) {
  console.log(key, value)
}

// 遍历 Set
const set = new Set([1, 2, 3])
for (const item of set) {
  console.log(item)
}

// 与 for...in 的区别
const obj = { a: 1, b: 2 }
for (const key in obj) {
  console.log(key) // 'a', 'b' (遍历键名)
}
// for...of 不能直接遍历普通对象

// 使用 break 和 continue
for (const item of arr) {
  if (item === 'b') break
  console.log(item)
}

12. 新的数据结构

Map

javascript
const map = new Map()

// 设置值
map.set('name', 'Alice')
map.set(1, 'number key')
map.set({ id: 1 }, 'object key')

// 获取值
map.get('name') // 'Alice'

// 检查存在
map.has('name') // true

// 删除
map.delete('name')

// 大小
map.size

// 清空
map.clear()

// 初始化
const map2 = new Map([
  ['a', 1],
  ['b', 2]
])

// 遍历
for (const [key, value] of map) {
  console.log(key, value)
}
map.forEach((value, key) => {
  console.log(key, value)
})

// 转换为数组
const arr = [...map]
const keys = [...map.keys()]
const values = [...map.values()]
const entries = [...map.entries()]

Set

javascript
const set = new Set()

// 添加值
set.add(1)
set.add(2)
set.add(2) // 重复值会被忽略

// 检查存在
set.has(1) // true

// 删除
set.delete(1)

// 大小
set.size

// 数组去重
const unique = [...new Set([1, 2, 2, 3, 3])] // [1, 2, 3]

// 集合运算
const setA = new Set([1, 2, 3])
const setB = new Set([2, 3, 4])

// 并集
const union = new Set([...setA, ...setB]) // {1, 2, 3, 4}

// 交集
const intersection = new Set([...setA].filter(x => setB.has(x))) // {2, 3}

// 差集
const difference = new Set([...setA].filter(x => !setB.has(x))) // {1}

WeakMap 和 WeakSet

javascript
// WeakMap - 键必须是对象,键是弱引用
const weakMap = new WeakMap()
let obj = { name: 'test' }
weakMap.set(obj, 'value')
obj = null // 键值对会被垃圾回收

// WeakSet - 值必须是对象,值是弱引用
const weakSet = new WeakSet()
let obj2 = { id: 1 }
weakSet.add(obj2)
obj2 = null // 会被垃圾回收

13. Symbol

javascript
// 创建唯一的 Symbol
const sym1 = Symbol()
const sym2 = Symbol('description') // 描述仅用于调试
const sym3 = Symbol('description') // sym2 !== sym3

// 全局 Symbol 注册表
const globalSym1 = Symbol.for('app.id')
const globalSym2 = Symbol.for('app.id') // 相同的 Symbol
globalSym1 === globalSym2 // true

// 获取 Symbol 的 key
Symbol.keyFor(globalSym1) // 'app.id'

// 作为对象属性键
const obj = {
  [Symbol('secret')]: 'private data',
  name: 'public'
}

// 内置 Symbol
const iterableObj = {
  data: [1, 2, 3],
  [Symbol.iterator]() {
    let index = 0
    return {
      next: () => {
        if (index < this.data.length) {
          return { value: this.data[index++], done: false }
        }
        return { done: true }
      }
    }
  }
}

// 其他内置 Symbol
// Symbol.toStringTag
// Symbol.toPrimitive
// Symbol.hasInstance
// Symbol.isConcatSpreadable
// Symbol.species
// Symbol.match, Symbol.replace, Symbol.search, Symbol.split

14. Proxy 和 Reflect

javascript
// Proxy - 代理对象
const target = {
  name: 'Alice',
  age: 25
}

const handler = {
  get(obj, prop) {
    console.log(`Getting ${prop}`)
    return obj[prop]
  },
  set(obj, prop, value) {
    console.log(`Setting ${prop} to ${value}`)
    obj[prop] = value
    return true
  },
  has(obj, prop) {
    return prop in obj
  },
  deleteProperty(obj, prop) {
    console.log(`Deleting ${prop}`)
    delete obj[prop]
    return true
  }
}

const proxy = new Proxy(target, handler)
proxy.name // Getting name
proxy.age = 26 // Setting age to 26

// 可撤销的 Proxy
const { proxy, revoke } = Proxy.revocable(target, handler)
revoke() // 撤销后访问会报错

// Reflect - 与 Proxy handler 方法一一对应
const obj = { name: 'test' }
Reflect.get(obj, 'name') // 'test'
Reflect.set(obj, 'age', 25) // true
Reflect.has(obj, 'name') // true
Reflect.deleteProperty(obj, 'age')
Reflect.ownKeys(obj) // ['name']

// 实际应用:数据绑定、验证、日志
function createReactiveObject(target, callback) {
  return new Proxy(target, {
    set(obj, prop, value) {
      const oldValue = obj[prop]
      obj[prop] = value
      callback(prop, value, oldValue)
      return true
    }
  })
}

15. 新增的数组方法

javascript
// Array.from() - 从类数组或可迭代对象创建数组
Array.from('hello') // ['h', 'e', 'l', 'l', 'o']
Array.from([1, 2, 3], x => x * 2) // [2, 4, 6]
Array.from({ length: 5 }, (_, i) => i) // [0, 1, 2, 3, 4]

// Array.of() - 创建数组
Array.of(1, 2, 3) // [1, 2, 3]
Array.of(7) // [7] (与 new Array(7) 不同)

// fill() - 填充数组
;[1, 2, 3].fill(0) // [0, 0, 0]
;[1, 2, 3].fill(0, 1) // [1, 0, 0]
;[1, 2, 3, 4].fill(0, 1, 3) // [1, 0, 0, 4]

// find() 和 findIndex()
const arr = [1, 2, 3, 4, 5]
arr.find(x => x > 3) // 4
arr.findIndex(x => x > 3) // 3

// copyWithin() - 数组内部复制
;[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]

// entries(), keys(), values()
for (const [index, value] of ['a', 'b'].entries()) {
  console.log(index, value)
}
for (const index of ['a', 'b'].keys()) {
  console.log(index)
}
for (const value of ['a', 'b'].values()) {
  console.log(value)
}

// includes() (ES2016)
;[1, 2, 3].includes(2) // true
;[1, 2, NaN].includes(NaN) // true

16. 新增的字符串方法

javascript
// includes(), startsWith(), endsWith()
'Hello World'.includes('World') // true
'Hello World'.startsWith('Hello') // true
'Hello World'.endsWith('World') // true
'Hello World'.startsWith('World', 6) // true

// repeat()
'abc'.repeat(3) // 'abcabcabc'
'ab'.repeat(0) // ''

// padStart(), padEnd() (ES2017)
'5'.padStart(3, '0') // '005'
'5'.padEnd(3, '0') // '500'
'hello'.padStart(10) // '     hello'

// trimStart(), trimEnd() (ES2019)
'  hello  '.trimStart() // 'hello  '
'  hello  '.trimEnd() // '  hello'

// at() (ES2022)
'hello'.at(0) // 'h'
'hello'.at(-1) // 'o' (支持负索引)

17. 新增的对象特性

javascript
// 对象属性简写
const name = 'Alice'
const age = 25
const person = { name, age } // { name: 'Alice', age: 25 }

// 方法简写
const obj = {
  greet() {
    return 'Hello'
  }
}

// 计算属性名
const key = 'dynamic'
const obj2 = {
  [key]: 'value',
  [`${key}Key`]: 'another value'
}

// Object.assign()
const merged = Object.assign({}, obj1, obj2)

// Object.is() - 严格相等比较
Object.is(NaN, NaN) // true (=== 为 false)
Object.is(-0, 0) // false (=== 为 true)
Object.is('hello', 'hello') // true

// Object.keys(), values(), entries()
Object.keys({ a: 1, b: 2 }) // ['a', 'b']
Object.values({ a: 1, b: 2 }) // [1, 2]
Object.entries({ a: 1, b: 2 }) // [['a', 1], ['b', 2]]

// Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors({ a: 1 })
// { a: { value: 1, writable: true, enumerable: true, configurable: true } }

// Object.setPrototypeOf() 和 Object.getPrototypeOf()
const proto = {
  greet() {
    return 'Hello'
  }
}
Object.setPrototypeOf(obj, proto)
Object.getPrototypeOf(obj) // proto

// Object.fromEntries() (ES2019)
Object.fromEntries([
  ['a', 1],
  ['b', 2]
]) // { a: 1, b: 2 }

18. 尾调用优化 (Tail Call Optimization)

javascript
// 正常递归 - 可能栈溢出
function factorial(n) {
  if (n <= 1) return 1
  return n * factorial(n - 1) // 不是尾调用
}

// 尾调用优化版本
function factorialOptimized(n, acc = 1) {
  if (n <= 1) return acc
  return factorialOptimized(n - 1, n * acc) // 尾调用
}

// 尾调用的条件:
// 1. 函数的最后一步是调用另一个函数
// 2. 调用函数后不再有其他操作
// 3. 返回值只依赖被调用函数的返回值

二、ES2016 (ES7) 新特性

1. Array.prototype.includes()

javascript
const arr = [1, 2, 3, NaN]

arr.includes(2) // true
arr.includes(4) // false
arr.includes(NaN) // true (与 indexOf 不同)

// 与 indexOf 的区别
;[NaN].indexOf(NaN) // -1
;[NaN].includes(NaN) // true

// 第二个参数:起始位置
;[1, 2, 3].includes(1, 1) // false

2. 指数运算符 (**)

javascript
// 基本用法
2 ** 3 // 8
3 ** 2 // 9
10 ** -1 // 0.1

// 右结合
2 ** (3 ** 2) // 512 (2 ** (3 ** 2))

// 赋值运算符
let a = 2
a **= 3 // a = 8

// 与 Math.pow 的区别
Math.pow(2, 3) // 8 (功能相同,但 ** 更简洁)

三、ES2017 (ES8) 新特性

1. async/await

javascript
// 基本用法
async function fetchUser() {
  try {
    const response = await fetch('/api/user')
    const user = await response.json()
    return user
  } catch (error) {
    console.error('Error:', error)
  }
}

// 并行执行
async function fetchAll() {
  const [users, posts] = await Promise.all([
    fetch('/api/users').then(r => r.json()),
    fetch('/api/posts').then(r => r.json())
  ])
  return { users, posts }
}

// async 函数返回 Promise
async function greet() {
  return 'Hello'
}
greet().then(msg => console.log(msg))

// 错误处理
async function handleErrors() {
  try {
    const result = await riskyOperation()
    return result
  } catch (error) {
    console.error(error)
    throw error // 重新抛出
  }
}

// 循环中的 await
async function processItems(items) {
  for (const item of items) {
    await processItem(item)
  }
}

// 立即执行 async 函数
;(async () => {
  const data = await fetchData()
  console.log(data)
})()

2. Object.values() 和 Object.entries()

javascript
const obj = { a: 1, b: 2, c: 3 }

Object.values(obj) // [1, 2, 3]
Object.entries(obj) // [['a', 1], ['b', 2], ['c', 3]]

// 实际应用
const prices = { apple: 1, banana: 2, orange: 3 }

// 计算总价
const total = Object.values(prices).reduce((sum, price) => sum + price, 0)

// 转换为 Map
const map = new Map(Object.entries(prices))

// 过滤对象
const filtered = Object.fromEntries(
  Object.entries(prices).filter(([_, price]) => price > 1)
)

3. 字符串填充方法

javascript
// padStart() - 左填充
'5'.padStart(3, '0') // '005'
'123'.padStart(5, '0') // '00123'
'hello'.padStart(10, '.') // '.....hello'

// padEnd() - 右填充
'5'.padEnd(3, '0') // '500'
'hello'.padEnd(10, '.') // 'hello.....'

// 实际应用:格式化
function formatNumber(num, length = 5) {
  return String(num).padStart(length, '0')
}
formatNumber(123) // '00123'

// 格式化货币
function formatCurrency(amount) {
  return '$' + amount.toFixed(2).padStart(8)
}

4. Object.getOwnPropertyDescriptors()

javascript
const obj = {
  name: 'Alice',
  get fullName() {
    return `${this.name} Smith`
  }
}

const descriptors = Object.getOwnPropertyDescriptors(obj)
// {
//   name: { value: 'Alice', writable: true, enumerable: true, configurable: true },
//   fullName: { get: [Function: get fullName], set: undefined, enumerable: true, configurable: true }
// }

// 实际应用:正确复制对象(包括 getter/setter)
function clone(obj) {
  return Object.create(
    Object.getPrototypeOf(obj),
    Object.getOwnPropertyDescriptors(obj)
  )
}

5. 函数参数尾逗号

javascript
// 允许在参数列表末尾添加逗号
function foo(
  param1,
  param2,
  param3 // 允许尾逗号
) {
  // ...
}

const obj = {
  name: 'Alice',
  age: 25,
  city: 'NYC' // 允许尾逗号
}

const arr = [
  1,
  2,
  3 // 允许尾逗号
]

6. SharedArrayBuffer 和 Atomics

javascript
// SharedArrayBuffer - 共享内存
const sharedBuffer = new SharedArrayBuffer(1024)
const sharedArray = new Int32Array(sharedBuffer)

// Atomics - 原子操作
Atomics.add(sharedArray, 0, 5) // 原子加
Atomics.load(sharedArray, 0) // 原子读取
Atomics.store(sharedArray, 0, 10) // 原子存储
Atomics.compareExchange(sharedArray, 0, 10, 20) // 条件交换

// 用于 Web Workers 之间的数据共享

四、ES2018 (ES9) 新特性

1. 异步迭代 (Asynchronous Iteration)

javascript
// 异步生成器
async function* asyncGenerator() {
  const urls = ['/api/1', '/api/2', '/api/3']
  for (const url of urls) {
    const response = await fetch(url)
    yield response.json()
  }
}

// for await...of 循环
async function processAsyncData() {
  for await (const data of asyncGenerator()) {
    console.log(data)
  }
}

// 异步迭代器协议
const asyncIterable = {
  [Symbol.asyncIterator]() {
    return {
      i: 0,
      next() {
        if (this.i < 3) {
          return Promise.resolve({ value: this.i++, done: false })
        }
        return Promise.resolve({ done: true })
      }
    }
  }
}

;(async () => {
  for await (const num of asyncIterable) {
    console.log(num)
  }
})()

2. 对象剩余属性和展开属性

javascript
// 对象剩余属性
const { a, ...rest } = { a: 1, b: 2, c: 3 }
console.log(rest) // { b: 2, c: 3 }

// 对象展开属性
const obj1 = { a: 1, b: 2 }
const obj2 = { c: 3, ...obj1 } // { c: 3, a: 1, b: 2 }

// 合并对象
const merged = { ...obj1, ...obj2 }

// 浅拷贝
const copy = { ...obj1 }

// 实际应用:移除属性
function removeProperty(obj, key) {
  const { [key]: _, ...rest } = obj
  return rest
}

3. Promise.prototype.finally()

javascript
fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error))
  .finally(() => {
    console.log('Request completed')
    // 无论成功或失败都会执行
    // 用于清理工作
  })

// 实际应用
async function withLoading(promise) {
  showLoading()
  try {
    return await promise
  } finally {
    hideLoading()
  }
}

4. 正则表达式增强

javascript
// s 标志 (dotAll) - . 匹配任意字符包括换行符
;/hello.world/s.test('hello\nworld') // true

// 命名捕获组
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
const match = dateRegex.exec('2024-01-15')
match.groups.year // '2024'
match.groups.month // '01'
match.groups.day // '15'

// 后行断言 (Lookbehind)
// 正向后行断言 (?<=...)
const priceRegex = /(?<=\$)\d+/
priceRegex.exec('Price: $100') // ['100']

// 负向后行断言 (?<!...)
const regex = /(?<!\$)\d+/
regex.exec('Price: $100') // null
regex.exec('Count: 100') // ['100']

// Unicode 属性转义
// \p{...} 匹配 Unicode 属性
;/\p{Script=Greek}+/u.test('π') // true
;/\p{Number}+/u.test('①②③') // true
;/\p{Emoji}/u.test('😊') // true

五、ES2019 (ES10) 新特性

1. Array.prototype.flat() 和 flatMap()

javascript
// flat() - 扁平化数组
;[1, [2, 3]].flat() // [1, 2, 3]
;[1, [2, [3, 4]]].flat() // [1, 2, [3, 4]]
;[1, [2, [3, 4]]].flat(2) // [1, 2, 3, 4]
;[1, [2, [3, 4]]].flat(Infinity) // [1, 2, 3, 4]

// flatMap() - 映射后扁平化
const sentences = ['Hello World', 'Hi There']
const words = sentences.flatMap(s => s.split(' '))
// ['Hello', 'World', 'Hi', 'There']

// 实际应用:过滤并映射
const numbers = [1, 2, 3, 4, 5]
const result = numbers.flatMap(n => (n % 2 === 0 ? [n, n * 2] : []))
// [2, 4, 4, 8]

2. Object.fromEntries()

javascript
// 从键值对数组创建对象
const entries = [
  ['a', 1],
  ['b', 2],
  ['c', 3]
]
Object.fromEntries(entries) // { a: 1, b: 2, c: 3 }

// Map 转对象
const map = new Map([
  ['name', 'Alice'],
  ['age', 25]
])
Object.fromEntries(map) // { name: 'Alice', age: 25 }

// URL 参数解析
const params = new URLSearchParams('name=Alice&age=25')
Object.fromEntries(params) // { name: 'Alice', age: '25' }

// 对象转换
const obj = { a: 1, b: 2, c: 3 }
const transformed = Object.fromEntries(
  Object.entries(obj).map(([key, value]) => [key.toUpperCase(), value * 2])
)
// { A: 2, B: 4, C: 6 }

3. 字符串 trim 方法增强

javascript
// trimStart() / trimLeft()
'  hello  '.trimStart() // 'hello  '
'  hello  '.trimLeft() // 'hello  '

// trimEnd() / trimRight()
'  hello  '.trimEnd() // '  hello'
'  hello  '.trimRight() // '  hello'

4. Symbol.prototype.description

javascript
const sym = Symbol('My description')
sym.description // 'My description'

const sym2 = Symbol()
sym2.description // undefined

const sym3 = Symbol.for('global')
sym3.description // 'global'

5. 可选的 catch 绑定

javascript
// 之前
try {
  // ...
} catch (error) {
  console.log('Error occurred')
}

// 现在 - 不需要 error 参数
try {
  // ...
} catch {
  console.log('Error occurred')
}

// 实际应用
function safeParse(json) {
  try {
    return JSON.parse(json)
  } catch {
    return null
  }
}

6. Array.prototype.sort() 稳定性

javascript
// ES2019 保证 sort() 是稳定排序
const students = [
  { name: 'Alice', grade: 90 },
  { name: 'Bob', grade: 90 },
  { name: 'Charlie', grade: 85 }
]

// 稳定排序:相同分数的元素保持原有顺序
students.sort((a, b) => b.grade - a.grade)
// Alice 仍在 Bob 之前

7. Function.prototype.toString() 修订

javascript
function foo() {
  /* comment */
}
foo.toString() // 返回完整的源代码,包括注释和空格

// 内置函数
Array.isArray.toString() // "function isArray() { [native code] }"

六、ES2020 (ES11) 新特性

1. 可选链操作符 (?.)

javascript
const user = {
  name: 'Alice',
  address: {
    city: 'NYC'
  }
}

// 之前
const city = user && user.address && user.address.city

// 现在
const city2 = user?.address?.city

// 函数调用
user.greet?.() // 如果 greet 存在则调用

// 数组访问
const first = arr?.[0]

// 与 nullish coalescing 结合
const name = user?.profile?.name ?? 'Anonymous'

// 各种形式
obj?.prop // 访问属性
obj?.[expr] // 访问动态属性
arr?.[index] // 访问数组元素
func?.(args) // 调用函数

2. 空值合并运算符 (??)

javascript
// 只在 null 或 undefined 时使用默认值
const value = null ?? 'default' // 'default'
const value2 = undefined ?? 'default' // 'default'
const value3 = '' ?? 'default' // '' (空字符串不是 null/undefined)
const value4 = 0 ?? 'default' // 0

// 与 || 的区别
const a = 0 || 'default' // 'default' (0 是 falsy)
const b = 0 ?? 'default' // 0 (0 不是 null/undefined)

const c = '' || 'default' // 'default'
const d = '' ?? 'default' // ''

// 短路求值
const x = null ?? console.log('evaluated') // 打印 'evaluated'
const y = 'value' ?? console.log('not evaluated') // 不打印

// 与可选链结合
const name = user?.profile?.name ?? 'Anonymous'

3. BigInt

javascript
// 创建 BigInt
const big1 = 9007199254740991n // 后缀 n
const big2 = BigInt(9007199254740991)
const big3 = BigInt('9007199254740991')

// 运算
const result = 9007199254740991n + 1n
const multiplied = big1 * 2n

// 比较
9007199254740991n === 9007199254740991 // true
9007199254740991n == 9007199254740991 // true

// 类型转换
Number(10n) // 10
BigInt(10) // 10n

// 不能混合运算
// 10n + 5; // TypeError
10n + BigInt(5) // 正确

// JSON 序列化问题
// JSON.stringify({ value: 10n }); // TypeError
// 解决方案
JSON.stringify({ value: 10n.toString() }) // '{"value":"10"}'

4. globalThis

javascript
// 统一的全局对象访问方式
// 浏览器: window
// Node.js: global
// Web Worker: self

// 现在统一使用
globalThis.setTimeout // 在任何环境都有效

// 之前需要检测环境
const getGlobal = () => {
  if (typeof self !== 'undefined') return self
  if (typeof window !== 'undefined') return window
  if (typeof global !== 'undefined') return global
  throw new Error('No global object found')
}

5. Promise.allSettled()

javascript
// 等待所有 Promise 完成(无论成功或失败)
const promises = [
  Promise.resolve(1),
  Promise.reject('error'),
  Promise.resolve(3)
]

Promise.allSettled(promises).then(results => {
  results.forEach(result => {
    if (result.status === 'fulfilled') {
      console.log('Success:', result.value)
    } else {
      console.log('Failed:', result.reason)
    }
  })
})
// [
//   { status: 'fulfilled', value: 1 },
//   { status: 'rejected', reason: 'error' },
//   { status: 'fulfilled', value: 3 }
// ]

// 实际应用:批量请求
async function fetchAllUrls(urls) {
  const results = await Promise.allSettled(
    urls.map(url => fetch(url).then(r => r.json()))
  )
  return {
    succeeded: results.filter(r => r.status === 'fulfilled').map(r => r.value),
    failed: results.filter(r => r.status === 'rejected').map(r => r.reason)
  }
}

6. String.prototype.matchAll()

javascript
const text = 'test1test2test3'
const regex = /t(e)(st(\d?))/g

// 之前需要循环调用 exec
// 现在可以使用 matchAll
const matches = [...text.matchAll(regex)]
// [
//   ['test1', 'e', 'st1', '1', index: 0, input: 'test1test2test3'],
//   ['test2', 'e', 'st2', '2', index: 5, input: 'test1test2test3'],
//   ['test3', 'e', 'st3', '3', index: 10, input: 'test1test2test3']
// ]

// 实际应用:提取所有匹配
const html = '<div>content1</div><div>content2</div>'
const divRegex = /<div>(.*?)<\/div>/g
const contents = [...html.matchAll(divRegex)].map(m => m[1])
// ['content1', 'content2']

7. 动态导入 (Dynamic Import)

javascript
// 静态导入
// import { add } from './math.js';

// 动态导入 - 返回 Promise
async function loadModule() {
  const module = await import('./math.js')
  return module.add(1, 2)
}

// 条件加载
if (condition) {
  import('./feature.js').then(module => {
    module.init()
  })
}

// 按需加载
button.addEventListener('click', async () => {
  const module = await import('./heavy-module.js')
  module.doSomething()
})

// 加载多个模块
async function loadAll() {
  const [math, utils] = await Promise.all([
    import('./math.js'),
    import('./utils.js')
  ])
  return { math, utils }
}

8. import.meta

javascript
// 获取模块元信息
console.log(import.meta.url) // 当前模块的 URL

// 在 Node.js 中
console.log(import.meta.url) // file:///path/to/module.js

// 判断是否在主模块
if (import.meta.url === `file://${process.argv[1]}`) {
  // 是主模块
}

// 动态导入相对路径
async function loadRelative(path) {
  const baseUrl = new URL('.', import.meta.url)
  return import(new URL(path, baseUrl).href)
}

9. for...in 顺序标准化

javascript
// ES2020 规范了 for...in 的遍历顺序
const obj = {
  a: 1,
  b: 2,
  2: 'two',
  1: 'one'
}

for (const key in obj) {
  console.log(key)
}
// 规范顺序: '1', '2', 'a', 'b'
// 数字键按数值升序,字符串键按添加顺序

七、ES2021 (ES12) 新特性

1. 逻辑赋值运算符

javascript
// ||= 或赋值
let a = false
a ||= 'default' // a = 'default'

// 等价于
a = a || 'default'

// &&= 与赋值
let b = 'value'
b &&= 'new value' // b = 'new value'

let c = false
c &&= 'new value' // c 仍然是 false

// ??= 空值合并赋值
let d = null
d ??= 'default' // d = 'default'

let e = 'value'
e ??= 'default' // e 仍然是 'value'

// 实际应用
const config = {
  timeout: 0,
  retries: null
}

config.timeout ??= 3000 // 不改变(0 不是 null/undefined)
config.retries ??= 3 // retries = 3
config.name ||= 'default' // name = 'default'

2. 数字分隔符

javascript
// 使用下划线分隔数字,提高可读性
const billion = 1_000_000_000
const bytes = 0xff_ff_ff_ff
const bits = 0b1010_0001_1000_0101
const octal = 0o1234_5670
const fractional = 1_000.000_001

// 可以在任意位置使用
const num = 1_2_3_4_5 // 12345

// 实际应用
const budget = 1_000_000
const mask = 0b1111_1111_1111_1111
const hexColor = 0xff_ff_ff

3. String.prototype.replaceAll()

javascript
// 替换所有匹配项
'hello world'.replaceAll('l', 'L') // 'heLLo worLd'

// 之前需要使用正则表达式全局标志
'hello world'.replace(/l/g, 'L')

// 使用正则表达式
'aabbcc'.replaceAll(/b/g, 'X') // 'aaXXcc'

// 特殊字符需要转义
'1.2.3'.replaceAll('.', '-') // '1-2-3'

4. Promise.any()

javascript
// 返回第一个成功的 Promise
const promises = [
  Promise.reject('error 1'),
  Promise.resolve('success 1'),
  Promise.resolve('success 2')
]

Promise.any(promises)
  .then(result => console.log(result)) // 'success 1'
  .catch(error => console.log('All failed'))

// 所有都失败时抛出 AggregateError
Promise.any([Promise.reject('error 1'), Promise.reject('error 2')]).catch(
  error => {
    console.log(error instanceof AggregateError) // true
    console.log(error.errors) // ['error 1', 'error 2']
  }
)

// 实际应用:请求多个服务器,使用最快响应的
async function fetchFromMultiple(urls) {
  return Promise.any(urls.map(url => fetch(url).then(r => r.json())))
}

5. WeakRef 和 FinalizationRegistry

javascript
// WeakRef - 弱引用对象
let obj = { data: 'large data' }
const weakRef = new WeakRef(obj)

// 获取对象(可能已被垃圾回收)
const dereferenced = weakRef.deref()
if (dereferenced) {
  console.log(dereferenced.data)
}

obj = null // 允许垃圾回收

// FinalizationRegistry - 对象被垃圾回收时的回调
const registry = new FinalizationRegistry(heldValue => {
  console.log(`Object with id ${heldValue} was garbage collected`)
})

function createObject(id) {
  const obj = { data: 'some data' }
  registry.register(obj, id)
  return obj
}

const temp = createObject('obj-1')
// 当 temp 被垃圾回收时,会调用回调

// 实际应用:缓存
class Cache {
  constructor() {
    this.cache = new Map()
    this.registry = new FinalizationRegistry(key => {
      this.cache.delete(key)
    })
  }

  set(key, value) {
    const ref = new WeakRef(value)
    this.cache.set(key, ref)
    this.registry.register(value, key)
  }

  get(key) {
    const ref = this.cache.get(key)
    return ref?.deref()
  }
}

八、ES2022 (ES13) 新特性

1. 顶层 await

javascript
// 在模块顶层直接使用 await
// 不需要包装在 async 函数中

// 之前
// async function init() {
//     const data = await fetch('/api/data');
//     return data.json();
// }

// 现在
const response = await fetch('/api/data')
const data = await response.json()

console.log(data)

// 动态加载模块
const module = await import('./feature.js')

// 条件加载
const config = await (process.env.NODE_ENV === 'production'
  ? import('./config.prod.js')
  : import('./config.dev.js'))

// 数据库连接
const db = await connectDB()

2. 类的私有字段和方法

javascript
class Person {
  // 私有字段(以 # 开头)
  #name
  #age

  // 私有静态字段
  static #count = 0

  constructor(name, age) {
    this.#name = name
    this.#age = age
    Person.#count++
  }

  // 私有方法
  #validate() {
    return this.#age > 0
  }

  // 公共方法访问私有成员
  getName() {
    if (this.#validate()) {
      return this.#name
    }
  }

  // 私有 getter/setter
  get #info() {
    return `${this.#name}, ${this.#age}`
  }

  // 静态私有方法
  static #getCount() {
    return Person.#count
  }

  // 静态块
  static {
    console.log('Person class initialized')
  }
}

// 外部无法访问私有成员
const person = new Person('Alice', 25)
// person.#name; // SyntaxError
// person.#validate(); // SyntaxError

3. 类的静态块

javascript
class Database {
  static connection
  static config = {
    host: 'localhost',
    port: 5432
  }

  // 静态初始化块
  static {
    // 执行复杂的静态初始化逻辑
    try {
      this.connection = createConnection(this.config)
      console.log('Database connected')
    } catch (error) {
      console.error('Connection failed:', error)
    }
  }

  static async query(sql) {
    return this.connection.execute(sql)
  }
}

// 多个静态块按顺序执行
class Example {
  static {
    console.log('Block 1')
  }
  static {
    console.log('Block 2')
  }
}

4. Array.prototype.at()

javascript
const arr = ['a', 'b', 'c', 'd', 'e']

// 正向索引
arr.at(0) // 'a'
arr.at(2) // 'c'

// 负向索引(从末尾开始)
arr.at(-1) // 'e'
arr.at(-2) // 'd'

// 与传统方式的对比
arr[arr.length - 1] // 'e'
arr.at(-1) // 'e' (更简洁)

// 字符串也支持
'hello'.at(-1) // 'o'

// 实际应用
function getLastItem(array) {
  return array.at(-1)
}

5. Object.hasOwn()

javascript
const obj = {
  name: 'Alice',
  age: 25
}

// 新方法
Object.hasOwn(obj, 'name') // true
Object.hasOwn(obj, 'age') // true
Object.hasOwn(obj, 'toString') // false

// 与 Object.prototype.hasOwnProperty.call 的区别
// 更安全,不依赖原型链
const obj2 = Object.create(null)
obj2.name = 'test'
// obj2.hasOwnProperty('name'); // TypeError
Object.hasOwn(obj2, 'name') // true

// 与 in 操作符的区别
'name' in obj // true
'toString' in obj // true (检查原型链)
Object.hasOwn(obj, 'toString') // false (只检查自有属性)

6. Error Cause

javascript
// 错误链 - 记录错误原因
try {
  await fetchData()
} catch (error) {
  throw new Error('Failed to process data', { cause: error })
}

// 捕获并查看原因
try {
  process()
} catch (error) {
  console.log(error.message) // 'Failed to process data'
  console.log(error.cause) // 原始错误
  console.log(error.cause.message) // 'Network error'
}

// 实际应用:错误追踪
async function saveUser(user) {
  try {
    await validateUser(user)
    await saveToDatabase(user)
  } catch (error) {
    throw new Error('User save failed', {
      cause: error,
      user: user.id
    })
  }
}

九、ES2023 (ES14) 新特性

1. 数组非破坏性方法

javascript
const arr = [3, 1, 4, 1, 5, 9]

// toSorted() - 返回排序后的新数组
const sorted = arr.toSorted() // [1, 1, 3, 4, 5, 9]
console.log(arr) // [3, 1, 4, 1, 5, 9] (原数组不变)

// toReversed() - 返回反转后的新数组
const reversed = arr.toReversed() // [9, 5, 1, 4, 1, 3]

// toSpliced() - 返回删除/插入元素后的新数组
const spliced = arr.toSpliced(2, 2, 'a', 'b')
// [3, 1, 'a', 'b', 5, 9]

// with() - 返回修改指定索引后的新数组
const modified = arr.with(0, 'first') // ['first', 1, 4, 1, 5, 9]

// 链式调用
const result = arr.toSorted().toReversed().with(0, 'biggest')

// 对比破坏性方法
arr.sort() // 原数组被修改
arr.toSorted() // 原数组不变

2. 从尾部查找数组元素

javascript
const arr = [1, 2, 3, 4, 3, 2, 1]

// findLast() - 从后向前查找
arr.findLast(x => x > 2) // 3

// findLastIndex() - 从后向前查找索引
arr.findLastIndex(x => x > 2) // 4

// 对比
arr.find(x => x > 2) // 3 (第一个)
arr.findLast(x => x > 2) // 3 (最后一个)

arr.findIndex(x => x > 2) // 2
arr.findLastIndex(x => x > 2) // 4

// 实际应用
const tasks = [
  { id: 1, status: 'done' },
  { id: 2, status: 'pending' },
  { id: 3, status: 'done' }
]

const lastDone = tasks.findLast(t => t.status === 'done')

3. Hashbang 语法

javascript
#!/usr/bin/env node

// 文件开头的 #! 被识别为 hashbang 注释
// 用于指定脚本的解释器

// example.js
#!/usr/bin/env node
console.log('Hello from script!');

// 可以直接执行:./example.js

4. Symbol 作为 WeakMap 的键

javascript
// 之前 WeakMap 的键只能是对象
// 现在 Symbol 也可以作为键

const weak = new WeakMap()
const key = Symbol('key')

weak.set(key, 'value')
weak.get(key) // 'value'

// 实际应用:私有数据存储
const privateData = new WeakMap()

class MyClass {
  constructor() {
    const key = Symbol('private')
    privateData.set(this, { key, secret: 'hidden' })
  }
}

十、ES2024 (ES15) 新特性

1. 数组分组方法

javascript
const students = [
  { name: 'Alice', grade: 'A' },
  { name: 'Bob', grade: 'B' },
  { name: 'Charlie', grade: 'A' },
  { name: 'David', grade: 'C' }
]

// Object.groupBy() - 返回对象
const byGrade = Object.groupBy(students, student => student.grade)
// {
//   A: [{ name: 'Alice', grade: 'A' }, { name: 'Charlie', grade: 'A' }],
//   B: [{ name: 'Bob', grade: 'B' }],
//   C: [{ name: 'David', grade: 'C' }]
// }

// Map.groupBy() - 返回 Map
const byGradeMap = Map.groupBy(students, student => student.grade)

// 实际应用
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const { even, odd } = Object.groupBy(numbers, n =>
  n % 2 === 0 ? 'even' : 'odd'
)

2. Promise.withResolvers()

javascript
// 之前创建 Promise 的方式
let resolve, reject
const promise = new Promise((res, rej) => {
  resolve = res
  reject = rej
})

// 新方法 - 更简洁
const { promise, resolve, reject } = Promise.withResolvers()

// 实际应用:事件转 Promise
function waitForEvent(emitter, eventName) {
  const { promise, resolve, reject } = Promise.withResolvers()

  emitter.once(eventName, data => {
    resolve(data)
  })

  emitter.once('error', error => {
    reject(error)
  })

  return promise
}

3. String.prototype.isWellFormed() 和 toWellFormed()

javascript
// 检查字符串是否包含代理对
const valid = 'Hello 😊'
const invalid = 'Hello \uD83D' // 不完整的代理对

valid.isWellFormed() // true
invalid.isWellFormed() // false

// 转换为格式正确的字符串
invalid.toWellFormed() // 'Hello �' (替换为替换字符)

// 实际应用:处理用户输入
function processText(text) {
  if (!text.isWellFormed()) {
    text = text.toWellFormed()
  }
  // 安全处理文本
}

4. Atomics.waitAsync()

javascript
// 异步等待共享内存的变化
const sharedBuffer = new SharedArrayBuffer(4)
const view = new Int32Array(sharedBuffer)

// 异步等待
async function waitForValue() {
  const result = Atomics.waitAsync(view, 0, 0)
  if (result.async) {
    await result.value
    console.log('Value changed!')
  }
}

// 用于跨 Worker 通信

5. 正则表达式 v 标志

javascript
// v 标志 - Unicode 字符串模式
const regex = /[\p{Emoji}]/v

// 支持集合操作
// 差集
;/[\p{Decimal_Number}--[0-9]]/v // 匹配非 ASCII 数字

// 交集
;/[\p{ASCII}&&\p{Letter}]/v // 匹配 ASCII 字母

// 并集
;/[[\p{ASCII}][\p{Emoji}]]/v // 匹配 ASCII 或 Emoji

十一、ES6+ 特性速查表

版本年份主要特性
ES62015let/const、箭头函数、类、模块、Promise、解构、展开运算符、Map/Set、Proxy、Symbol
ES72016Array.includes()、指数运算符(**)
ES82017async/await、Object.values/entries、字符串填充、尾逗号
ES92018异步迭代、对象剩余/展开、Promise.finally()、正则增强
ES102019flat/flatMap、Object.fromEntries、trimStart/End、可选catch
ES112020可选链(?.)、空值合并(??)、BigInt、globalThis、动态import、allSettled
ES122021逻辑赋值、数字分隔符、replaceAll、Promise.any、WeakRef
ES132022顶层await、私有字段、静态块、at()、hasOwn()、Error Cause
ES142023toSorted/toReversed/toSpliced/with、findLast、Hashbang
ES152024groupBy、Promise.withResolvers、isWellFormed、正则v标志

十二、最佳实践建议

1. 变量声明

javascript
// 优先使用 const
const PI = 3.14159
const config = { timeout: 3000 }

// 需要重新赋值时使用 let
let count = 0
count++

// 避免使用 var

2. 异步编程

javascript
// 优先使用 async/await
async function fetchData() {
  try {
    const response = await fetch('/api/data')
    return response.json()
  } catch (error) {
    console.error(error)
  }
}

// 并行任务使用 Promise.all
const [users, posts] = await Promise.all([fetchUsers(), fetchPosts()])

// 容错场景使用 allSettled
const results = await Promise.allSettled(tasks)

3. 对象和数组操作

javascript
// 使用解构提取数据
const { name, age } = user
const [first, ...rest] = items

// 使用展开运算符复制
const newObj = { ...obj, newProp: 'value' }
const newArr = [...arr, newItem]

// 使用可选链安全访问
const city = user?.address?.city

// 使用空值合并提供默认值
const name = user?.name ?? 'Anonymous'

4. 模块化

javascript
// 使用 ES 模块
export function add(a, b) {
  return a + b
}
import { add } from './math.js'

// 动态导入大型模块
const heavy = await import('./heavy-module.js')

5. 类的设计

javascript
class UserService {
  #apiUrl
  #cache = new Map()

  constructor(apiUrl) {
    this.#apiUrl = apiUrl
  }

  async getUser(id) {
    if (this.#cache.has(id)) {
      return this.#cache.get(id)
    }
    const user = await this.#fetchUser(id)
    this.#cache.set(id, user)
    return user
  }

  async #fetchUser(id) {
    const response = await fetch(`${this.#apiUrl}/users/${id}`)
    return response.json()
  }
}

总结

ES6 及后续版本的更新使 JavaScript 成为更现代、更强大的编程语言。主要改进包括:

  1. 更好的作用域控制:let/const 提供块级作用域
  2. 更简洁的语法:箭头函数、解构、展开运算符
  3. 面向对象增强:类、私有字段、静态块
  4. 异步编程改进:Promise、async/await、异步迭代
  5. 模块化支持:ES 模块、动态导入
  6. 更好的数据处理:Map/Set、数组方法增强
  7. 更安全的代码:可选链、空值合并、Proxy
  8. 更好的开发者体验:数字分隔符、模板字符串

建议开发者持续关注 ECMAScript 的最新发展,合理使用新特性来提高代码质量和开发效率。

基于 VitePress 的本地知识库