ES6+ 语言特性

从 ES2015 到 ES2024,按年份梳理 JavaScript 关键语言特性。区分日常高频用法与了解级知识点,帮助你在面试中精准表达对现代 JS 演进的理解。

为什么要系统了解 ES6+ 特性

面试中常见的"你了解哪些 ES6 新特性"只是入口问题。真正考察的是:你能否说清楚每个特性解决了什么问题在哪个 ES 版本引入、以及它与旧方案的本质区别。系统梳理可以让回答从"罗列 API"升级为"展现语言演进的理解力"。


ES2015 (ES6) — 里程碑版本

ES2015 是 JavaScript 有史以来最大的一次语法升级,几乎重塑了日常编码方式。

let / const 与块级作用域 ⭐ 日常高频

var 是函数作用域(function-scoped),而 letconst 是块级作用域(block-scoped)。

核心差异:

  • Temporal Dead Zone (TDZ)let/const 在声明之前的区域内访问会抛出 ReferenceError,而 var 会返回 undefined(hoisting 行为不同)
  • const 的不可变性:绑定不可重新赋值,但对象/数组的内部属性仍然可变(immutable binding, mutable value)
  • 不会挂载到 globalThis:在顶层用 let/const 声明不会成为 window 属性
// TDZ 示例
console.log(x); // ReferenceError — TDZ
let x = 1;

// const 对象可变
const config = { port: 3000 };
config.port = 8080; // ✅ 合法
config = {};         // ❌ TypeError

面试要点:能说清 TDZ 的机制和 const 可变性这两个细节,就能体现对变量声明的深入理解。

解构赋值(Destructuring) ⭐ 日常高频

从数组或对象中提取值并绑定到变量,支持默认值、重命名和嵌套。

// 对象解构 + 重命名 + 默认值
const { name: userName = 'Anonymous', age } = user;

// 数组解构 + 跳过元素
const [first, , third] = [1, 2, 3];

// 函数参数解构
function connect({ host = 'localhost', port = 3306 } = {}) {
  // 注意末尾的 = {} 防止调用时不传参导致 TypeError
}

// 嵌套解构
const { address: { city } } = user; // 注意:address 本身不会被绑定为变量

面试要点:参数解构末尾的 = {} 防御性写法,以及嵌套解构中"中间层不会成为变量"这两个点值得提及。

扩展运算符与剩余参数(Spread / Rest) ⭐ 日常高频

... 在不同语法位置有不同含义:

  • Spread(展开):用于函数调用、数组字面量、对象字面量
  • Rest(收集):用于函数参数、解构赋值
// Spread — 浅拷贝对象(ES2018 引入对象 spread)
const merged = { ...defaults, ...overrides };

// Rest — 收集剩余属性
const { id, ...rest } = response.data;

// 注意:spread 是浅拷贝(shallow copy)
const original = { nested: { a: 1 } };
const copy = { ...original };
copy.nested.a = 2; // original.nested.a 也变成 2

模板字面量(Template Literals) ⭐ 日常高频

反引号包裹的字符串,支持插值表达式和多行。

const greeting = `Hello, ${user.name}!`;

// Tagged Template Literals — 高级用法
function sql(strings, ...values) {
  // strings: ['SELECT * FROM users WHERE id = ', '']
  // values: [userId]
  return sanitize(strings, values);
}
const query = sql`SELECT * FROM users WHERE id = ${userId}`;

Tagged Template Literals 是 styled-components、GraphQL(gql)等库的底层机制,面试中提到这个会加分。

箭头函数(Arrow Functions) ⭐ 日常高频

  • 没有自己的 this,继承外层词法作用域的 this(lexical this
  • 没有 arguments 对象
  • 不能用作构造函数(没有 [[Construct]]prototype
  • 没有 super 绑定
// 经典场景:回调中保持 this
class Timer {
  start() {
    setInterval(() => {
      this.tick(); // this 指向 Timer 实例
    }, 1000);
  }
}

Symbol ⭐ 了解级

ES2015 引入的第七种原始类型。每次 Symbol() 调用都生成唯一值。

核心用途

  1. 唯一属性键:避免命名冲突,在框架/库中广泛使用
  2. Well-known SymbolsSymbol.iteratorSymbol.toPrimitiveSymbol.hasInstance 等,用于定制对象的内置行为
  3. 全局注册表Symbol.for(key) 可跨 realm 共享同一个 Symbol
// 自定义迭代行为
const range = {
  [Symbol.iterator]() {
    let current = this.from;
    return {
      next: () => current <= this.to
        ? { value: current++, done: false }
        : { done: true }
    };
  },
  from: 1,
  to: 5
};
for (const n of range) console.log(n); // 1 2 3 4 5

面试要点:不需要记住所有 well-known symbols,但能说出 Symbol.iteratorSymbol.toPrimitive 的用途即可。

Set / Map / WeakMap / WeakSet ⭐ 日常高频(Map/Set)· 了解级(Weak 系列)

数据结构 键类型 是否可迭代 GC 行为 典型场景
Set 值(任意) 强引用 数组去重、集合运算
Map 键(任意) 强引用 非字符串键的键值对
WeakMap 键(仅对象) 弱引用,键可被 GC 私有数据关联、缓存
WeakSet 值(仅对象) 弱引用 标记/追踪对象
// WeakMap 经典用法:关联私有数据
const privateData = new WeakMap();
class User {
  constructor(name) {
    privateData.set(this, { name });
  }
  getName() {
    return privateData.get(this).name;
  }
}
// 当 User 实例被 GC 时,WeakMap 中对应的条目也会自动清除

Map vs Object 的关键区别:Map 的键可以是任意类型;Map 保留插入顺序;Map 有 size 属性;Map 在频繁增删键值对时性能更好。

其他 ES2015 重要特性

  • Class 语法:语法糖,底层仍是 prototype chain(详见 prototype-chain 专题)
  • Promise:异步编程基础(详见 async-programming 专题)
  • for...of:统一的迭代协议,可遍历任何实现了 Symbol.iterator 的对象
  • Generator 函数function* + yield(详见 iterators-generators 专题)
  • 默认参数、计算属性名、Object.assign

ES2016 (ES7) — 小版本

特性 频率 说明
Array.prototype.includes() ⭐ 日常高频 替代 indexOf() !== -1,支持 NaN 判断
指数运算符 ** 了解级 2 ** 10 等价于 Math.pow(2, 10)

ES2017 (ES8)

特性 频率 说明
async / await ⭐ 日常高频 详见 async-programming 专题
Object.values() / Object.entries() ⭐ 日常高频 对象遍历的常用工具
String.prototype.padStart/padEnd 了解级 字符串填充
Object.getOwnPropertyDescriptors 了解级 配合 Object.defineProperties 做精确拷贝
Trailing commas in function params 了解级 减少 git diff 噪音

ES2018 (ES9)

特性 频率 说明
对象 rest/spread 属性 ⭐ 日常高频 const { a, ...rest } = obj;
Promise.finally() ⭐ 日常高频 无论 resolve/reject 都执行的清理逻辑
Async iteration(for await...of 了解级 用于异步迭代器,如逐行读取流
正则增强(Named capture groups、Lookbehind) 了解级 (?<year>\d{4})(?<=\$)\d+

ES2019 (ES10)

特性 频率 说明
Array.prototype.flat() / flatMap() ⭐ 日常高频 数组扁平化,flatMap 等价于 map + flat(1)
Object.fromEntries() ⭐ 日常高频 Object.entries() 的逆操作
String.prototype.trimStart/trimEnd 了解级 单侧去空白
可选的 catch 参数 了解级 catch { ... } 无需声明 error 变量

ES2020 (ES11) — 重要版本

Optional Chaining ?. ⭐ 日常高频

安全访问深层嵌套属性,短路返回 undefined

// 属性访问
const city = user?.address?.city;

// 方法调用
const result = obj.method?.();

// 动态属性
const value = obj?.[dynamicKey];

注意?. 只检查左侧是否为 nullundefined,其他 falsy 值(0''false)不会触发短路。

Nullish Coalescing ?? ⭐ 日常高频

仅在左侧为 nullundefined 时取右侧默认值,与 || 的区别是不会将 0''false 视为需要默认的值。

const port = config.port ?? 3000;    // 如果 port 为 0,保留 0
const port2 = config.port || 3000;   // 如果 port 为 0,变成 3000 ← 通常不符合预期

面试必问??|| 的区别。核心是 falsy vs nullish 的语义差异。

其他 ES2020 特性

特性 频率 说明
Promise.allSettled() ⭐ 日常高频 等待所有 promise settle,不会因某个 reject 而短路
Dynamic import() ⭐ 日常高频 运行时按需加载模块,返回 Promise
globalThis 了解级 跨环境(browser/Node/Worker)统一获取全局对象
BigInt 了解级 任意精度整数,123n,不能与 Number 混合运算

ES2021 (ES12)

特性 频率 说明
String.prototype.replaceAll() ⭐ 日常高频 不再需要 /pattern/g 正则来替换所有
逻辑赋值运算符 &&= ||= ??= ⭐ 日常高频 a ??= b 等价于 a ?? (a = b)
Promise.any() 了解级 第一个 fulfill 即 resolve;全部 reject 则抛 AggregateError
数字分隔符 _ 了解级 1_000_000 增强可读性
WeakRef / FinalizationRegistry 了解级 弱引用与垃圾回收回调,极少直接使用

ES2022 (ES13) — 重要版本

Top-level await ⭐ 日常高频

在 ES Module 的顶层直接使用 await,不再需要包裹 async IIFE。

// config.js (ESM)
const response = await fetch('/api/config');
export const config = await response.json();

注意:仅在 ESM 中可用;会阻塞依赖该模块的其他模块的加载(模块图变成异步)。

Class 增强

class Counter {
  // 公有实例字段
  count = 0;

  // 私有字段(# 前缀)
  #limit = 100;

  // 私有方法
  #validate() { return this.count < this.#limit; }

  // 静态私有字段
  static #instances = 0;

  // 静态初始化块
  static {
    console.log('Counter class initialized');
  }
}

其他 ES2022 特性

特性 频率 说明
Array.prototype.at() ⭐ 日常高频 arr.at(-1) 获取最后一个元素
Object.hasOwn() ⭐ 日常高频 替代 Object.prototype.hasOwnProperty.call(obj, key)
Error.cause ⭐ 日常高频 throw new Error('msg', { cause: err }) 错误链
正则 /d flag (indices) 了解级 匹配结果中包含起止位置索引

ES2023 (ES14)

不可变数组方法 ⭐ 日常高频

返回新数组而非原地修改,与 React 等强调 immutable state 的框架高度契合。

新方法 对应的可变方法
toSorted() sort()
toReversed() reverse()
toSpliced() splice()
with(index, value) 下标直接赋值
const sorted = arr.toSorted((a, b) => a - b); // arr 不变
const replaced = arr.with(2, 'new');            // arr 不变

其他 ES2023 特性

特性 频率 说明
findLast() / findLastIndex() ⭐ 日常高频 从数组末尾向前搜索
Hashbang (#!) 支持 了解级 CLI 脚本的 shebang 行:#!/usr/bin/env node

ES2024 (ES15)

特性 频率 说明
Object.groupBy() / Map.groupBy() ⭐ 日常高频 按条件分组,替代 lodash _.groupBy
Promise.withResolvers() ⭐ 日常高频 解构出 { promise, resolve, reject },告别手动 Deferred 模式
ArrayBuffer.prototype.resize() 了解级 可调整大小的 ArrayBuffer
String.prototype.isWellFormed() 了解级 检测是否有孤立的 surrogate
Atomics.waitAsync() 了解级 非阻塞的原子等待
// Object.groupBy
const grouped = Object.groupBy(users, user =>
  user.age >= 18 ? 'adult' : 'minor'
);
// { adult: [...], minor: [...] }

// Promise.withResolvers
const { promise, resolve, reject } = Promise.withResolvers();
setTimeout(() => resolve('done'), 1000);

Import Assertions / Import Attributes 了解级

注意:import assertionsassert 语法)已在 Stage 3 被重命名为 Import Attributeswith 语法)。

// 旧语法(已弃用)
import data from './data.json' assert { type: 'json' };

// 新语法(Import Attributes)
import data from './data.json' with { type: 'json' };

用途:告诉运行时如何解释被导入的模块,主要用于 JSON modules 和 CSS modules。目前浏览器和 Node.js 支持度仍在推进中。


面试中如何组织回答

当被问到"说说你了解的 ES6+ 特性"时,避免纯罗列。推荐按问题域分类来组织:

  1. 变量与作用域let/const、块级作用域、TDZ
  2. 数据处理:解构、spread/rest、Array.prototype.at()、不可变数组方法、Object.groupBy()
  3. 异步编程:Promise → async/awaitPromise.allSettled/any → top-level awaitPromise.withResolvers()
  4. 模块系统:ESM import/export → dynamic import() → import attributes
  5. 类型与元编程:Symbol、Proxy/Reflect(详见 proxy-reflect 专题)
  6. 安全编码:optional chaining、nullish coalescing、Error.cause

这样的结构既展示了广度,也体现了对语言演进脉络的理解。


高频 vs 了解级 速查表

⭐ 日常高频(面试必须掌握)

let/const、解构赋值、spread/rest、模板字面量、箭头函数、Set/Mapasync/await?. optional chaining、?? nullish coalescing、Promise.allSettled()、dynamic import()、逻辑赋值运算符、top-level awaitArray.prototype.at()、不可变数组方法(toSorted 等)、Object.groupBy()Promise.withResolvers()

📖 了解级(知道用途和动机即可)

Symbol(及 well-known symbols)、WeakMap/WeakSetWeakRef/FinalizationRegistryBigIntglobalThis、Async iteration、Import Attributes、Atomics.waitAsync()

延展阅读