JavaScript ES6+ (ES2015~ES2024) 全特性整理

47 阅读8分钟

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:统一对象操作 API
  • Proxy:对象代理(拦截读写、调用等)
// 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''falsenull、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 || 1010
a &&= 5;  // 等价 a = a && 55
a ??= 20; // 等价 a = a ??205

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 {}

总结

  1. 核心基础:ES6 奠定了现代 JS 的语法(let/const、解构、类、Promise、模块化);
  2. 异步进化:Promise → async/await 成为异步编程标配;
  3. 便捷语法:可选链?.、空值合并??、展开运算符...大幅简化代码;
  4. 数据安全:私有字段#、Proxy/Reflect、WeakMap 强化对象操作;
  5. 数组增强:flat、at、不可变方法让数组操作更高效。

所有特性均为浏览器 / Node.js 最新版原生支持,可直接在项目中使用。