Skip to content

JavaScript ES6+ 全部特性

ES6(ES2015)至 ES2024 的全部重要特性,覆盖日常开发中最高频的语法。


变量声明

let / const

js
// const —— 常量,不可重新赋值
const API_URL = 'https://api.example.com'
const MAX_SIZE = 100

// let —— 块级作用域变量
let count = 0
count++

// ❌ const 不能重新赋值
// API_URL = 'xxx' // TypeError

// ⚠️ const 对象/数组的内部可以修改
const user = { name: '张三' }
user.name = '李四' // ✅ 修改属性
// user = {}       // ❌ 重新赋值

const list = [1, 2, 3]
list.push(4) // ✅ 修改内容
// list = []  // ❌ 重新赋值

解构赋值

js
// ---- 数组解构 ----
const [first, second, third] = [1, 2, 3]
const [head, ...tail] = [1, 2, 3, 4]
// head = 1, tail = [2, 3, 4]

// 跳过元素
const [, second] = [1, 2, 3] // second = 2

// 默认值
const [posX = 0, posY = 0] = [1] // posX = 1, posY = 0

// ---- 对象解构 ----
const { name, age } = { name: '张三', age: 25 }

// 重命名
const { name: userName, age: userAge } = { name: '张三', age: 25 }

// 默认值
const { role = 'user', status = 'active' } = {}

// 嵌套解构
const { address: { city } } = { address: { city: '北京' } } // city = '北京'

// 剩余属性
const { id, ...userInfo } = { id: 1, name: '张三', age: 25 }
// userInfo = { name: '张三', age: 25 }

解构的常见用法

js
// 函数参数解构
function createUser({ name, age, role = 'user' }) {
  return { name, age, role }
}

// 交换变量
let swapA = 1, swapB = 2
;[swapA, swapB] = [swapB, swapA] // swapA = 2, swapB = 1

// 从 API 响应提取数据
const { data: { user, token } } = await api.login(credentials)

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

箭头函数

js
// 基本语法
const add = (a, b) => a + b
const square = (n) => n * n
const greet = () => 'hello'

// 函数体有多条语句
const calculate = (a, b) => {
  const sum = a + b
  return sum * 2
}

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

// 高阶函数常用
const numbers = [1, 2, 3, 4, 5]
const doubled = numbers.map((n) => n * 2)
const evens = numbers.filter((n) => n % 2 === 0)
const sum = numbers.reduce((acc, n) => acc + n, 0)

箭头函数 vs 普通函数

特性箭头函数普通函数
this继承外层(词法 this)调用时绑定
arguments没有
prototype没有
构造函数不能 new可以 new
yield不能用可以用
js
// ❌ 不适合用箭头函数的场景
const obj = {
  name: '张三',
  // 方法:this 会丢失
  greet: () => {
    console.log(this.name) // undefined
  },
  // ✅ 用简写方法
  greet() {
    console.log(this.name) // '张三'
  },
}

模板字符串

js
const name = '张三'
const age = 25

// 基本用法
const msg = `我叫 ${name},今年 ${age} 岁`

// 多行
const html = `
  <div class="card">
    <h2>${name}</h2>
    <p>年龄:${age}</p>
  </div>
`

// 表达式
const price = 100
const text = `总价:${price * 0.8} 元(八折)`

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

const highlighted = highlight`用户 ${name} 的年龄是 ${age}`
// "用户 <mark>张三</mark> 的年龄是 <mark>25</mark>"

展开运算符与剩余参数

js
// ---- 展开运算符 ----
// 数组展开(ES2015)
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
const merged = [...arr1, ...arr2] // [1, 2, 3, 4, 5, 6]

// 对象展开(ES2018)
const defaults = { theme: 'light', lang: 'zh-CN' }
const userConfig = { theme: 'dark' }
const config = { ...defaults, ...userConfig } // { theme: 'dark', lang: 'zh-CN' }

// 浅拷贝
const copy = { ...original }
const arrCopy = [...original]

// ---- 剩余参数 ----
function sum(...numbers) {
  return numbers.reduce((acc, n) => acc + n, 0)
}
sum(1, 2, 3) // 6

function log(first, ...rest) {
  console.log('第一个:', first)
  console.log('其余:', rest)
}
log('a', 'b', 'c', 'd')
// 第一个: a
// 其余: ['b', 'c', 'd']

对象增强

js
const name = '张三'
const age = 25

// 属性简写
const user = { name, age } // 等价于 { name: name, age: age }

// 方法简写
const obj = {
  // 等价于 greet: function () { ... }
  greet() {
    return 'hello'
  },
}

// 计算属性名
const key = 'color'
const style = {
  [key]: 'red',
  [`${key}Size`]: '14px',
}
// { color: 'red', colorSize: '14px' }

// 可选链(?.)
const city = user?.address?.city // undefined(不会报错)

// 空值合并(??)
const port = config.port ?? 3000 // 只有 null/undefined 才用默认值
const port2 = config.port || 3000 // 0, '', false 也会用默认值

数组常用方法

数组的完整方法(增删、查找、遍历、排序、转换等)详见 数据类型与内置方法 - Array 原型方法

以下为 ES6+ 新增的数组方法:

flat / flatMap(ES2019)

js
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)  // 完全扁平化

const sentences = ['hello world', 'foo bar']
const words = sentences.flatMap((s) => s.split(' '))
// ['hello', 'world', 'foo', 'bar']

at(ES2022)

js
const arr = [1, 2, 3, 4, 5]
arr.at(0)    // 1
arr.at(-1)   // 5(最后一个)
arr.at(-2)   // 4(倒数第二个)

findLast / findLastIndex(ES2023)

js
const arr = [1, 2, 3, 4, 5]
arr.find((x) => x > 3)          // 4(从前往后)
arr.findLast((x) => x > 3)      // 5(从后往前)
arr.findIndex((x) => x > 3)     // 3
arr.findLastIndex((x) => x > 3) // 4

Promise

大白话解释: Promise 就像"点外卖等通知"。你下单(发起异步操作),外卖小哥去取餐(执行中),然后你会收到通知:

  • 成功(resolve):餐到了,可以吃了
  • 失败(reject):餐厅关门了,订单取消

为什么要用 Promise?

  • 解决回调地狱:不用层层嵌套回调函数,代码更易读
  • 链式调用.then().then().then() 像流水线一样
  • 错误处理:一个 .catch() 捕获所有错误
  • 并行执行Promise.all() 同时执行多个异步操作

Promise 的三种状态:

  • Pending:等待中(外卖还没到)
  • Fulfilled:成功(餐到了)
  • Rejected:失败(订单取消)

基本用法

js
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功')
    // reject(new Error('失败'))
  }, 1000)
})

promise
  .then((result) => console.log(result))
  .catch((error) => console.error(error))
  .finally(() => console.log('结束'))

Promise 静态方法

js
// Promise.all —— 全部成功才成功
const results = await Promise.all([
  fetch('/api/user'),
  fetch('/api/orders'),
  fetch('/api/settings'),
])

// Promise.allSettled —— 等待全部完成(不论成败)
const outcomes = await Promise.allSettled([
  fetch('/api/a'),
  fetch('/api/b'),
])
// [{ status: 'fulfilled', value: ... }, { status: 'rejected', reason: ... }]

// Promise.race —— 最快的结果(不论成功失败)
const fastest = await Promise.race([
  fetch('/api/fast'),
  new Promise((_, reject) => setTimeout(() => reject('超时'), 5000)),
])

// Promise.any —— 最快的成功结果
const firstSuccess = await Promise.any([
  fetch('/api/a'),
  fetch('/api/b'),
  fetch('/api/c'),
])

常见模式

js
// 串行执行
async function sequential() {
  const user = await fetchUser()
  const orders = await fetchOrders(user.id)
  const details = await fetchOrderDetails(orders[0].id)
  return details
}

// 并行执行
async function parallel() {
  const [user, settings] = await Promise.all([
    fetchUser(),
    fetchSettings(),
  ])
  return { user, settings }
}

// 限制并发数
async function limitConcurrency(tasks, limit) {
  const results = []
  const executing = new Set()

  for (const task of tasks) {
    const p = task().then((result) => {
      executing.delete(p)
      return result
    })
    executing.add(p)
    results.push(p)

    if (executing.size >= limit) {
      await Promise.race(executing)
    }
  }

  return Promise.all(results)
}

async / await

大白话解释: async/await 是 Promise 的"语法糖"。让异步代码看起来像同步代码,更易读。

  • async:声明一个函数是异步的
  • await:暂停等待 Promise 完成,拿到结果后继续执行

为什么要用 async/await?

  • 代码更易读:不用写 .then(),像写同步代码一样
  • 错误处理更简单:用 try/catch 捕获错误
  • 调试更方便:可以像调试同步代码一样打断点

async/await vs Promise.then:

  • Promise.then:链式调用,适合简单的异步操作
  • async/await:更易读,适合复杂的异步流程
js
// 基本用法
async function fetchUser() {
  try {
    const res = await fetch('/api/user')
    if (!res.ok) throw new Error(`HTTP ${res.status}`)
    const data = await res.json()
    return data
  } catch (error) {
    console.error('获取用户失败:', error)
    throw error
  }
}

// 箭头函数
const getUser = async (id) => {
  const res = await fetch(`/api/user/${id}`)
  return res.json()
}

// for 循环中的 await(串行)
async function processItems(items) {
  for (const item of items) {
    await processItem(item) // 一个一个执行
  }
}

// for 循环中的 await(并行)
async function processItemsParallel(items) {
  await Promise.all(items.map((item) => processItem(item))) // 同时执行
}

错误处理

js
// 方案一:try/catch
async function fetchData() {
  try {
    const data = await riskyOperation()
    return data
  } catch (error) {
    return defaultValue
  }
}

// 方案二:toTuple 模式
async function toTuple(promise) {
  try {
    const result = await promise
    return [null, result]
  } catch (error) {
    return [error, null]
  }
}

const [err, data] = await toTuple(fetchUser())
if (err) {
  console.error('失败:', err)
} else {
  console.log('成功:', data)
}

Map 与 Set

Map

js
const map = new Map()

map.set('name', '张三')
map.set(1, 'one')
map.set(true, 'yes')

map.get('name') // '张三'
map.has(1)      // true
map.size        // 3
map.delete(1)

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

// 与对象的区别
// - Map 的 key 可以是任意类型
// - Map 有 size 属性
// - Map 可直接遍历
// - Map 在频繁增删场景性能更好

Set

js
const set = new Set([1, 2, 3, 2, 1])
// Set { 1, 2, 3 }

set.add(4)
set.has(2)   // true
set.delete(1)
set.size     // 3

// 数组去重
const unique = [...new Set([1, 2, 2, 3, 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}

模块化

导出

js
// utils/math.js

// 命名导出
export const PI = 3.14159
export function add(a, b) { return a + b }
export function multiply(a, b) { return a * b }

// 默认导出(每个模块只能一个)
export default class Calculator {
  // ...
}

导入

js
// 命名导入
import { add, multiply, PI } from './utils/math'

// 默认导入
import Calculator from './utils/math'

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

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

// 动态导入(按需加载)
const module = await import('./utils/math')
module.add(1, 2)

ES2016

js
// Array.prototype.includes
const arr = [1, 2, 3, NaN]
arr.includes(2)       // true
arr.includes(4)       // false
arr.includes(NaN)     // true(indexOf 找不到 NaN)

// 指数运算符
2 ** 10               // 1024
2 ** 3                // 8
let base = 2
base **= 3            // base = 8(等价于 base = base ** 3)

ES2017

js
// Object.entries / Object.values(ES2017 正式标准)
const obj = { a: 1, b: 2, c: 3 }
Object.entries(obj)   // [['a',1], ['b',2], ['c',3]]
Object.values(obj)    // [1, 2, 3]

// Object.getOwnPropertyDescriptors(ES2017,获取所有属性的描述符)
// 常用于浅拷贝对象(包括 getter/setter)
const source = {
  _name: '张三',
  get name() { return this._name },
  set name(value) { this._name = value },
}

const descs = Object.getOwnPropertyDescriptors(source)
// {
//   _name: { value: '张三', writable: true, enumerable: true, configurable: true },
//   name: { get: [Function], set: [Function], enumerable: true, configurable: true }
// }

// ❌ 展开运算符会丢失 getter/setter
const copy1 = { ...source } // copy1.name 是值,不是 getter/setter

// ✅ 用 getOwnPropertyDescriptors + defineProperties 完整拷贝
const copy2 = Object.defineProperties({}, descs)
copy2.name // '张三'(仍是 getter)

// 函数参数尾逗号
function foo(
  a,
  b,
  c,  // ✅ 允许尾逗号
) {}

const arr = [
  1,
  2,
  3,  // ✅
]

// String.prototype.padStart / padEnd(字符串填充)
'5'.padStart(3, '0')    // '005'
'hello'.padEnd(10, '!') // 'hello!!!!!'
'hi'.padStart(5)        // '   hi'(默认用空格填充)

// SharedArrayBuffer / Atomics(多线程,略)

ES2018

js
// 对象展开 / 剩余属性(已在 ES6 章节介绍)
const { a, ...rest } = { a: 1, b: 2, c: 3 }
const merged = { ...obj1, ...obj2 }

// Promise.prototype.finally
fetch('/api/data')
  .then((res) => res.json())
  .catch((err) => console.error(err))
  .finally(() => {
    loading.value = false // 无论成功失败都执行
  })

// 异步迭代(for-await-of)
async function processPages(urls) {
  for await (const response of urls.map((url) => fetch(url))) {
    const data = await response.json()
    console.log(data)
  }
}

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

// 正则:反向断言(lookbehind)
'hello world'.match(/(?<=hello\s)world/)  // ['world']
'hello world'.match(/(?<!hello\s)world/)  // null

// 正则:s 标志(dotAll,. 匹配换行符)
/./s.test('\n') // true

ES2019

js
// Array.prototype.flat / flatMap
;[1, [2, [3]]].flat()       // [1, 2, [3]]
;[1, [2, [3]]].flat(Infinity) // [1, 2, 3]
;[1, 2, 3].flatMap((x) => [x, x * 2]) // [1, 2, 2, 4, 3, 6]

// Object.fromEntries(entries 的逆操作)
Object.fromEntries([['a', 1], ['b', 2]]) // { a: 1, b: 2 }

// 将 URLSearchParams 转对象
const params = new URLSearchParams('a=1&b=2')
Object.fromEntries(params) // { a: '1', b: '2' }

// String.prototype.trimStart / trimEnd
'  hello  '.trimStart() // 'hello  '
'  hello  '.trimEnd()   // '  hello'

// 可选的 catch 绑定
try {
  // ...
} catch {  // 不需要 (error) 参数
  console.log('出错了')
}

// Symbol.prototype.description
Symbol('foo').description // 'foo'

ES2020

js
// 可选链(?.)—— 已在「对象增强」章节介绍
// 空值合并(??)—— 已在「对象增强」章节介绍

// BigInt
const big = 9007199254740991n
const big2 = BigInt('9007199254740991')
big + 1n  // 9007199254740992n
big === BigInt(9007199254740991) // true
typeof big // 'bigint'

// String.prototype.matchAll(返回所有匹配的迭代器)
const str = 'test1test2test3'
const regex = /test(\d)/g
const matches = [...str.matchAll(regex)]
// [['test1','1'], ['test2','2'], ['test3','3']]

// Promise.allSettled —— 已在 Promise 章节介绍

// globalThis(统一的全局对象引用)
// 浏览器:globalThis === window
// Node.js:globalThis === global
// Worker:globalThis === self
console.log(globalThis) // 跨环境获取全局对象

// 动态 import —— 已在模块化章节介绍

// import.meta
console.log(import.meta.url) // 当前模块的 URL

ES2021

js
// String.prototype.replaceAll
'hello world'.replaceAll('o', '0') // 'hell0 w0rld'
'aabbcc'.replaceAll(/b/g, 'x')     // 'aaxxcc'

// Promise.any(最快的成功结果)
const first = await Promise.any([
  fetch('/api/a'),
  fetch('/api/b'),
  fetch('/api/c'),
])
// AggregateError:全部失败时抛出

// 逻辑赋值运算符
let count = 0
let username = null
let fallback = undefined

count ||= 5     // count = count || 5 → count = 5(count 是假值时赋值)
count &&= 10    // count = count && 10 → count = 10(count 是真值时赋值)
username ??= '匿名'  // username = username ?? '匿名' → username = '匿名'(username 是 null/undefined 时赋值)
fallback ??= 'ok'  // fallback = 'ok'

// 数值分隔符(提高大数字可读性)
const billion = 1_000_000_000
const bytes = 0xFF_FF_FF_FF
const binary = 0b1010_0001_1000_0101
const hex = 0xA0_B0_C0

// WeakRef(弱引用)
// 什么是弱引用?正常情况下,只要变量引用了一个对象,这个对象就不会被垃圾回收。
// 弱引用不会阻止垃圾回收,当原对象没有其他引用时,垃圾回收器会回收它。

// 什么时候用弱引用?
// 1. 缓存大对象:缓存可能被回收,下次访问时重新计算
// 2. 避免内存泄漏:DOM 节点被移除后,引用也能自动失效
// 3. 追踪第三方库实例:不阻止它们被回收

let obj = { data: 'large' }
const ref = new WeakRef(obj)
obj = null // 原对象可被垃圾回收
// ref.deref() 可能返回 undefined(已被回收)或原对象

// FinalizationRegistry(垃圾回收回调)
// 什么时候用?当对象被垃圾回收时,执行清理操作(如关闭连接、释放资源)
const registry = new FinalizationRegistry((heldValue) => {
  console.log(`${heldValue} 被回收了`)
})
registry.register(someObject, 'myObject')

ES2022

js
// Array.prototype.at(负数索引)
const arr = [1, 2, 3, 4, 5]
arr.at(0)    // 1
arr.at(-1)   // 5
arr.at(-2)   // 4

// Object.hasOwn(替代 hasOwnProperty)
const obj = { a: 1 }
Object.hasOwn(obj, 'a')    // true
Object.hasOwn(obj, 'b')    // false
Object.hasOwn({}, 'toString') // false(原型上的不算)

// Error.cause(错误链)
try {
  // ...
} catch (err) {
  throw new Error('包装错误', { cause: err })
}

// 正则 /d 标志(返回匹配的开始和结束索引)
const result = 'hello'.match(/l/dg)
// result.indices: [[2, 3], [3, 4]]

// 顶层 await(在模块顶层直接使用 await)
// 只在 ES Module 中有效
const data = await fetch('/api/data').then((r) => r.json())
export { data }

// class 字段声明
class Person {
  // 公有字段
  name = '张三'

  // 私有字段(外部不可访问)
  #age = 25

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

  // 静态公有字段
  static count = 0

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

  // 静态块(初始化复杂静态属性)
  static {
    // 可以访问私有字段
    Person.#total = 100
  }

  getAge() {
    return this.#age
  }
}

const person = new Person()
console.log(person.name)   // '张三'
// console.log(person.#age) // ❌ SyntaxError
console.log(person.getAge()) // 25

ES2023

js
// Array.prototype.findLast / findLastIndex(从后往前找)
const arr = [1, 2, 3, 4, 5]

arr.find((x) => x > 3)          // 4(从前往后,第一个)
arr.findLast((x) => x > 3)      // 5(从后往前,第一个)

arr.findIndex((x) => x > 3)     // 3(从前往后)
arr.findLastIndex((x) => x > 3) // 4(从后往前)

// Array.prototype.toSorted / toReversed / toSpliced / with(ES2023,不修改原数组)
const nums = [3, 1, 4, 1, 5]

// toSorted:返回排序后的新数组(不修改原数组)
const sorted = nums.toSorted((a, b) => a - b) // [1, 1, 3, 4, 5]
console.log(nums) // [3, 1, 4, 1, 5](原数组不变)

// toReversed:返回反转后的新数组
const reversed = nums.toReversed() // [5, 1, 4, 1, 3]
console.log(nums) // [3, 1, 4, 1, 5](原数组不变)

// toSpliced:返回增删后的新数组(替代 splice)
const letters = ['a', 'b', 'c', 'd']
const spliced = letters.toSpliced(1, 2, 'x', 'y') // ['a', 'x', 'y', 'd']
console.log(letters) // ['a', 'b', 'c', 'd'](原数组不变)

// with:返回替换指定索引后的新数组
const items = [1, 2, 3, 4, 5]
const updated = items.with(2, 99) // [1, 2, 99, 4, 5]
console.log(items) // [1, 2, 3, 4, 5](原数组不变)

// 💡 为什么要用这些方法?
// Vue 3 的响应式系统依赖引用变化来触发更新
// 直接修改原数组(sort/reverse/splice)可能不会触发响应式更新
// 使用 toSorted/toReversed 等返回新数组的方式更安全
const list = ref([3, 1, 2])
list.value = list.value.toSorted() // ✅ 触发响应式更新

ES2024

js
// Symbol.dispose / Symbol.asyncDispose(显式资源管理)
// using 关键字自动在代码块结束时调用清理函数,类似 C# 的 using 或 Python 的 with

class FileWriter {
  #path
  #handle

  constructor(path) {
    this.#path = path
    this.#handle = openFile(path)
  }

  write(data) {
    this.#handle.write(data)
  }

  // 同步释放
  [Symbol.dispose]() {
    this.#handle.close()
    console.log(`${this.#path} 已关闭`)
  }
}

// using:离开作用域时自动调用 Symbol.dispose
{
  using file = new FileWriter('output.txt')
  file.write('hello')
} // 自动关闭文件

// await using:异步释放资源,配合 Symbol.asyncDispose
class DatabaseConnection {
  #connection
  constructor(url) { this.#connection = connect(url) }
  query(sql) { return this.#connection.execute(sql) }
  [Symbol.dispose]() { this.#connection.close() }
  async [Symbol.asyncDispose]() { await this.#connection.closeAsync() }
}

{
  await using db = new DatabaseConnection('postgres://...')
  await db.query('SELECT 1')
} // 自动异步关闭连接

// Object.groupBy / Map.groupBy(数组分组)
const people = [
  { name: '张三', age: 25 },
  { name: '李四', age: 30 },
  { name: '王五', age: 25 },
]

const grouped = Object.groupBy(people, (person) => person.age)
// {
//   25: [{ name: '张三', age: 25 }, { name: '王五', age: 25 }],
//   30: [{ name: '李四', age: 30 }]
// }

// Promise.withResolvers(创建 Promise 的便捷方式)
const { promise, resolve, reject } = Promise.withResolvers()
setTimeout(() => resolve('done'), 1000)
const result = await promise

// String.prototype.isWellFormed / toWellFormed(ES2024,处理 Unicode 字符串)
// 什么是"格式良好"的字符串?不包含孤立代理项(lone surrogate)的字符串
// 代理项是 UTF-16 编码中用于表示超出 BMP 范围字符的特殊码元

// 孤立代理项示例
const bad = 'hello\uD800world' // 包含孤立的高位代理项
bad.isWellFormed() // false

// isWellFormed:检查字符串是否格式良好
'hello'.isWellFormed()              // true
'hello\uD800world'.isWellFormed()   // false

// toWellFormed:将孤立代理项替换为 U+FFFD(替换字符)
'hello\uD800world'.toWellFormed() // 'hello�world'

// 实际应用:处理用户输入或外部数据时的安全检查
function safeString(str) {
  return str.isWellFormed() ? str : str.toWellFormed()
}

// Array.fromAsync(ES2024,从异步可迭代对象创建数组)
// 类似 Array.from,但支持异步迭代器和 Promise 数组

// 从 Promise 数组创建
const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]
const results = await Array.fromAsync(promises) // [1, 2, 3]

// 从异步迭代器创建
async function* generate() {
  yield 1
  yield 2
  yield 3
}
const arr = await Array.fromAsync(generate()) // [1, 2, 3]

// 带 mapFn(第二个参数)
const doubled = await Array.fromAsync([Promise.resolve(1), Promise.resolve(2)], (x) => x * 2)
// [2, 4]

// 错误处理:如果某个 Promise 失败,会抛出错误
try {
  await Array.fromAsync([Promise.resolve(1), Promise.reject(new Error('fail'))])
} catch (err) {
  console.error(err) // Error: fail
}

版本特性速查表

版本重要特性
ES2015 (ES6)let/const、箭头函数、解构、模板字符串、Promise、class、Module、Symbol、Map/Set
ES2016Array.includes** 指数运算符
ES2017async/awaitObject.entries/valuespadStart/padEndObject.getOwnPropertyDescriptors、尾逗号
ES2018对象展开/剩余、Promise.finally、正则命名捕获组、for-await-of
ES2019Array.flat/flatMapObject.fromEntriestrimStart/trimEnd、可选 catch 绑定
ES2020可选链 ?.、空值合并 ??BigIntPromise.allSettledglobalThismatchAll、动态 import
ES2021replaceAllPromise.any、逻辑赋值 `
ES2022Array.atObject.hasOwnError.cause、顶层 await、class 私有字段/方法、正则 /d 标志
ES2023Array.findLast/findLastIndextoSorted/toReversed/toSpliced/with
ES2024Object.groupByPromise.withResolversSymbol.dispose/using 资源管理、isWellFormed/toWellFormedArray.fromAsync

Vue 项目中的 ES6+ 实际应用

js
// ---- 解构:组合式 API 中提取响应式数据 ----
import { ref, computed } from 'vue'
const { count, increment } = useCounter() // 自定义 Hook 返回解构

// ---- 展开运算符:透传 Props ----
const props = defineProps({ name: String, age: Number })
const extraProps = { ...props, role: 'admin' }

// ---- 可选链 + 空值合并:安全访问嵌套数据 ----
const cityName = user?.address?.city ?? '未知城市'

// ---- Promise.all:并行请求 ----
const [userRes, orderRes] = await Promise.all([
  fetch('/api/user'),
  fetch('/api/orders'),
])

// ---- Map/Set:去重和快速查找 ----
const selectedIds = new Set([1, 2, 3])
const isSelected = (id) => selectedIds.has(id) // O(1) 查找

// ---- 模板字符串:动态 class/style ----
const btnClass = `btn btn-${variant ?? 'default'} btn-${size ?? 'md'}`

// ---- Object.entries:遍历配置对象 ----
const themeVars = { '--primary': '#1890ff', '--radius': '4px' }
Object.entries(themeVars).forEach(([key, value]) => {
  document.documentElement.style.setProperty(key, value)
})

参考

个人学习笔记,部分内容借助 AI 辅助整理,仅供查阅参考,请以官方文档为准