ES6+ 是 ES2015(ES6) 及之后每年发布的 ECMAScript 标准统称,是 JavaScript 现代化的核心。本文按年份版本分类,覆盖语法特性、新增 API、数据结构、运算符,所有特性均附可直接运行的代码示例。
一、ES2015 (ES6) —— 史上最大更新
核心:块级作用域、解构、类、模块化、Promise、新数据结构
1. 变量声明:let / const
- 块级作用域(
{}内有效) - 无变量提升、禁止重复声明
const声明常量(引用类型可修改属性)
// let 块级作用域
if (true) {
let a = 10;
}
// console.log(a); // 报错:未定义
// const 常量
const obj = { name: "张三" };
obj.name = "李四"; // 允许(修改属性)
// obj = {}; // 报错:重新赋值
2. 解构赋值
数组 / 对象快速提取值,支持嵌套、默认值
// 数组解构
const [a, b, ...rest] = [1, 2, 3, 4];
console.log(a, b, rest); // 1 2 [3,4]
// 对象解构
const { name, age = 18 } = { name: "张三" };
console.log(name, age); // 张三 18
// 嵌套解构
const { user: { id } } = { user: { id: 100 } };
3. 函数增强
箭头函数
- 无
this、无arguments、不能用作构造函数
const sum = (a, b) => a + b;
console.log(sum(1,2)); // 3
参数默认值 + 剩余参数 + 展开运算符
// 默认值
function fn(x = 0) { return x; }
// 剩余参数
function sum(...nums) { return nums.reduce((a,b)=>a+b); }
// 展开运算符
const arr1 = [1,2];
const arr2 = [...arr1, 3,4]; // [1,2,3,4]
4. 数组新增 API
const arr = [1, 2, 3, 4];
// 1、Array.from(要转换的对象, 遍历处理函数, this指向):类数组→数组
- 第 1 个参数:**必填**,待转换的类数组 / 可迭代对象
- 第 2 个参数:**可选**,类似 `map`,转换时直接处理每个元素
- 第 3 个参数:**可选**,指定处理函数的 `this`
- **返回新数组**:不会修改原对象
- **语法简洁**:替代老式写法 `[].slice.call(类数组)`
//1.转换 DOM 集合(最常用)
// 获取所有div(NodeList 类数组)
const divs = document.querySelectorAll('div');
// 转成真正的数组
const arr = Array.from(divs);
// 现在可以使用数组方法了
arr.map(div => div.textContent);
//2. 转换函数 arguments
function fn() {
// arguments → 真数组
const args = Array.from(arguments);
console.log(args); // [1,2,3]
}
fn(1,2,3);
//3. 字符串 → 数组
Array.from('hello'); // ['h','e','l','l','o']
//4. Set / Map → 数组
const set = new Set([1,2,3]);
const arr = Array.from(set); // [1,2,3]
const map = new Map([['a',1],['b',2]]);
Array.from(map); // [['a',1],['b',2]]
//5. 快速生成数组(进阶用法)
// 生成 [0,1,2,3,4]
const arr = Array.from({length:5}, (_, i) => i);
//6. 转换 + 处理元素(一步到位)
// 把 [1,2,3] 转数组并 ×2
const arr = Array.from([1,2,3], item => item * 2);
console.log(arr); // [2,4,6]
// 2、Array.of():创建数组
Array.of(1,2,3); // [1,2,3]
// 3、find()/findIndex():查找元素/索引
arr.find(item => item > 2); // 3
arr.findIndex(item => item > 2); // 2
// 4、fill():填充数组
new Array(3).fill(0); // [0,0,0]
// 5、entries()/keys()/values():迭代器
for (let [idx, val] of arr.entries()) {}
- `arr.entries()` 返回迭代器,每一项是 `[索引, 值]` 数组
- `[idx, val]` 是**数组解构**,直接把迭代器返回的数组拆分成索引和值
- 这是前端开发**最常用**的遍历方式(同时需要索引和值)
迭代器不能直接打印查看,用**扩展运算符 `...`** 转数组:
const arr = ['a', 'b', 'c'];
console.log([...arr.entries()]); // [[0,'a'], [1,'b'], [2,'c']]
console.log([...arr.keys()]); // [0,1,2]
console.log([...arr.values()]); // ['a','b','c']
5. 对象增强
const name = "张三";
// 1. 属性简写
const obj = { name };
// 2. 方法简写
const obj2 = { say() {} };
// 3. 计算属性名
const key = "age";
const obj3 = { [key]: 18 };
// Object.assign():合并对象
const target = {};
Object.assign(target, {a:1}, {b:2}); // {a:1,b:2}
// Object.is():严格相等(修复NaN、±0问题)
Object.is(NaN, NaN); // true
Object.is(+0, -0); // false
6. 字符串增强
// 模板字符串
const str = `姓名:${name}`;
// 新API
'hello'.includes('ll'); // true
'hello'.startsWith('he'); // true
'hello'.endsWith('lo'); // true
'hi'.repeat(3); // 'hihihi'
7. 新原始类型:Symbol
唯一不可变的值,解决对象属性名冲突
const s1 = Symbol('desc');
const s2 = Symbol('desc');
console.log(s1 === s2); // false
// 全局Symbol
const s3 = Symbol.for('key');
const s4 = Symbol.for('key');
console.log(s3 === s4); // true
8. 新数据结构:Set / WeakSet / Map / WeakMap
// Set:无重复值的集合
const set = new Set([1,2,2,3]);
set.add(4);
set.has(2); // true
[...set]; // [1,2,3,4]
// Map:键可以是任意类型的字典
const map = new Map();
map.set({id:1}, '值');
map.get({id:1}); // 注意:引用类型不相等
// WeakSet/WeakMap:弱引用,不阻止垃圾回收(只能存对象)
9. 异步:Promise
解决回调地狱,异步编程标准
const p = new Promise((resolve, reject) => {
setTimeout(() => resolve('成功'), 1000);
});
p.then(res => console.log(res)).catch(err => console.log(err));
10. 类:class
语法糖,基于原型的面向对象
class Person {
constructor(name) {
this.name = name;
}
// 实例方法
say() { console.log(this.name); }
// 静态方法
static fn() {}
}
const p = new Person('张三');
11. 模块化:import / export
// 导出
export const a = 1;
export default fn;
// 导入
import fn, { a } from './module.js';
12. 全局对象新增 API
Number
// 重点:不转类型!字符串、布尔值直接返回false
Number.isFinite(10); // true
Number.isNaN(NaN); // true
Number.parseInt('123abc'); // 123
Math
Math.trunc(4.9); // 4(取整)
Math.sign(-5); // -1(正负判断)
Reflect / Proxy
Reflect:统一对象操作 APIProxy:对象代理(拦截读写、调用等)
// Proxy 代理
const proxy = new Proxy({}, {
get(target, prop) { return 100; }
});
console.log(proxy.name); // 100
二、ES2016 (ES7) —— 小更新
1. 数组:Array.prototype.includes()
判断数组是否包含指定值(替代indexOf !== -1)
[1,2,3].includes(2); // true
[NaN].includes(NaN); // true(indexOf无法判断)
2. 指数运算符:**
2 ** 3; // 8(等价于 Math.pow(2,3))
三、ES2017 (ES8)
1. 异步终极方案:async / await
基于 Promise 的同步写法
async function getData() {
const res = await Promise.resolve('数据');
console.log(res);
}
2. 对象新增 API
const obj = {a:1, b:2};
Object.values(obj); // [1,2]
Object.entries(obj); // [['a',1],['b',2]]
Object.getOwnPropertyDescriptors(obj); // 获取属性描述符
3. 字符串填充:padStart() / padEnd()
- 第一个参数:**最终字符串要达到的长度**
- 第二个参数:用来填充的字符(可选,默认是空格)
'5'.padStart(2, '0'); // '05'
'5'.padEnd(2, '0'); // '50'
4. 函数参数尾逗号
function fn(a, b,) {} // 允许最后一个参数后加逗号
四、ES2018 (ES9)
1. Promise.finally()
无论成功 / 失败都会执行
Promise.resolve().finally(() => console.log('执行完毕'));
2. 对象展开运算符
const obj = {a:1};
const newObj = {...obj, b:2}; // {a:1,b:2}
3. 异步迭代:for-await-of
async function asyncIter() {
const promises = [Promise.resolve(1), Promise.resolve(2)];
for await (const val of promises) {
console.log(val);
}
}
4. 正则增强
命名捕获组、dotAll、反向断言等
const reg = /(?<year>\d{4})-(?<month>\d{2})/;
const { groups } = '2024-05'.match(reg);
console.log(groups.year); // 2024
五、ES2019 (ES10)
1. 数组扁平化:flat() / flatMap()
[1, [2, [3]]].flat(2); // [1,2,3]
[1,2].flatMap(x => [x, x*2]); // [1,2,2,4]
2. 对象:Object.fromEntries()
Map/entries → 对象(Object.entries逆操作)
const entries = [['a',1],['b',2]];
Object.fromEntries(entries); // {a:1,b:2}
3. 字符串修剪:trimStart() / trimEnd()
' hello '.trimStart(); // 'hello '
' hello '.trimEnd(); // ' hello'
4. 可选catch绑定
try {} catch {} // 无需写 (err)
六、ES2020 (ES11)
1. 空值合并运算符:??
仅null/undefined时触发默认值(区别于||)
## 逻辑或 `||`
只要左边是 **假值(falsy)** 就取右边:
`0、''、false、null、undefined、NaN` 都会触发默认值。
## 空值合并 `??`
只有 **`null / undefined`** 才触发默认值。
const a = 0 ?? 10; // 0
const b = false ?? 10; // false
const c = null ?? 10; // 10
2. 可选链操作符:?.
安全访问嵌套属性,避免报错
const obj = {};
obj?.user?.name; // undefined(不报错)
arr?.[0]; // 安全访问数组元素
3. 大整数:BigInt
处理超过2^53-1的大数字
const big = 1000000000000000000n;
BigInt(100) === 100n; // true
4. 全局对象:globalThis
-
浏览器里:
globalThis === window -
Node.js 里:
globalThis === global -
Web Worker 里:
globalThis === self -
统一浏览器 / Node.js 全局对象(
window/global)
globalThis.setTimeout === setTimeout; // true
5. Promise:allSettled()
等待所有 Promise 完成(无论成功 / 失败)
- 批量操作(上传、下载、导入)
- 需要**展示每个任务的状态**,允许部分失败
- 不关心失败,只需要知道所有任务执行完
Promise.allSettled([p1, p2]).then(res => {});
七、ES2021 (ES12)
1. 逻辑赋值运算符
let a = 0;
a ||= 10; // 等价 a = a || 10 → 10
a &&= 5; // 等价 a = a && 5 →5
a ??= 20; // 等价 a = a ??20 →5
2. 数字分隔符
const num = 1_000_000; // 1000000(可读性增强)
3. 字符串:replaceAll()
全局替换(无需正则/g)
'a-b-c'.replaceAll('-', '/'); // 'a/b/c'
4. Promise:any()
返回第一个成功的 Promise
- `race()` = **看速度**,第一个不管好坏直接返回
- `any()` = **看结果**,只认第一个成功的,失败全跳过
Promise.any([p1, p2]).then(res => {});
八、ES2022 (ES13)
1. 类私有字段(#)
真正的私有属性,外部无法访问
class Person {
#age = 18; // 私有实例字段
getAge() { return this.#age; }
}
const p = new Person();
// p.#age; // 报错
2. 数组:at()
支持负索引访问元素
[1,2,3].at(-1); // 3(最后一个元素)
3. 对象:Object.hasOwn()
替代hasOwnProperty,更安全
- `obj.hasOwnProperty()`:**实例方法**,要通过对象自己调用
- `Object.hasOwn()`:**静态方法**,通过 `Object` 调用,把对象当参数传进去
Object.hasOwn({a:1}, 'a'); // true
4. 错误原因:Error.cause
throw new Error('错误', { cause: '网络异常' });
九、ES2023 (ES14)
1. 数组反向查找:findLast() / findLastIndex()
[1,2,3,2].findLast(x => x === 2); // 2
2. 数组不可变方法
不修改原数组,返回新数组(替代旧API会改变原数组的方法)
const arr = [3,1,2];
arr.toReversed(); // [2,1,3](原数组不变)
arr.toSorted(); // [1,2,3]
arr.toSpliced(1,1); // [3,2]
arr.with(0, 10); // [10,1,2]
十、ES2024 (ES15) —— 最新标准
1. Promise:Promise.withResolvers()
简化 Promise 创建(无需包裹函数)
const { promise, resolve, reject } = Promise.withResolvers();
2. 分组:Object.groupBy() / Map.groupBy()
数组按条件分组
const arr = [1,2,3,4];
const group = Object.groupBy(arr, item => item % 2 === 0 ? '偶数' : '奇数');
// { 奇数: [1,3], 偶数: [2,4] }
3. 数组:Array.fromAsync()
异步迭代器转数组
const arr = await Array.fromAsync(asyncIterable);
4. 装饰器(正式纳入)
function log(target) { console.log('装饰器'); }
@log
class A {}
总结
- 核心基础:ES6 奠定了现代 JS 的语法(let/const、解构、类、Promise、模块化);
- 异步进化:Promise → async/await 成为异步编程标配;
- 便捷语法:可选链
?.、空值合并??、展开运算符...大幅简化代码; - 数据安全:私有字段
#、Proxy/Reflect、WeakMap 强化对象操作; - 数组增强:flat、at、不可变方法让数组操作更高效。
所有特性均为浏览器 / Node.js 最新版原生支持,可直接在项目中使用。