自从ES6(ECMAScript 2015)以来,JavaScript作为一门语言经历了前所未有的变革,每年的新版本都带来了令人振奋的新特性和优化,极大地提升了开发者的生产力和代码的可维护性。本文将深入探讨从ES6到ES15(ECMAScript 2024)期间JavaScript的演变历程,旨在为开发者提供一份全面的指南,涵盖语言的关键更新和实用示例。

JavaScript的现代进阶:从ES6到ES15看这一篇就够了

1. ES6 (ECMAScript 2015): 现代 JavaScript 的起点

1.1 let 和 const

  • let:块级作用域,避免变量提升带来的问题
  • const:不可重新赋值的常量
let count = 0;
const PI = 3.14;

1.2 解构赋值

const { firstName, lastName } = { firstName: 'John', lastName: 'Doe' };
console.log(firstName, lastName); // John Doe
const [first, second] = [1, 2];
console.log(first, second); // 1 2

1.3 模板字符串

const name = 'Alice';
console.log(`Hello, ${name}!`); // Hello, Alice!

1.4 箭头函数

const add = (a, b) => a + b;
add(1, 2); // 3

1.5 类

class Person {
  constructor(name) {
    this.name = name;
  }
  greet() {
    console.log(`Hello, ${this.name}`);
  }
}

const person = new Person('John');
person.greet();

1.6 模块系统

// myModule.js
export const PI = 3.14;

// main.js
import { PI } from './myModule.js';

1.7 Promises

const promise = new Promise((resolve) => {
  setTimeout(() => resolve('Done!'), 1000);
});
console.log(promise);

1.8 Symbols

const uniqueId = Symbol('id');
console.log(uniqueId);

1.9 Array.from()

const arrayLike = { length: 3, 0: 'a', 1: 'b', 2: 'c' };
const arr = Array.from(arrayLike);
console.log(arr);

1.10 Map 和 Set citeturn8view1

const myMap = new Map();
myMap.set('key1', 'value1');
myMap.set(123, 'another value');
console.log(myMap.get('key1')); // value1
console.log(myMap.size);        // 2

const mySet = new Set();
mySet.add('a');
mySet.add('b');
mySet.add('a');
console.log(mySet.has('a')); // true
console.log(mySet.size);     // 2

1.11 Array.of() citeturn8view1

const arr = Array.of(1, 2, 3);
console.log(arr);

1.12 生成器函数 function*() {} citeturn8view1

function* numberGenerator() {
  yield 1;
  yield 2;
  return 'done';
}

const gen = numberGenerator();
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());

1.13 默认参数和剩余参数 citeturn8view2

function sum(a = 10, ...nums) {
  return a + nums.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum()); // 10

function sum2(...nums) {
  return nums.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum2(1, 2, 3, 4)); // 10

1.14 String.prototype.repeat() citeturn8view2

const str = 'abc'.repeat(3);
console.log(str); // abcabcabc

2. ES7 (ECMAScript 2016): 数学运算的提升 citeturn8view2

2.1 指数运算符 (**)

const result = 2 ** 3;
console.log(result); // 8

3. ES8 (ECMAScript 2017): 异步编程的革命 citeturn8view2

3.1 async/await

async function fetchData() {
  const response = await fetch('/data');
  return await response.json();
}

3.2 扩展运算符 (…)

const arr = [...[1, 2], ...[3, 4]];
console.log(arr);

3.3 Array.prototype.includes()

const arr = [1, 2, 3];
console.log(arr.includes(2)); // true

3.4 padStart / padEnd

console.log('123'.padStart(7, '0')); // 0000123
console.log('123'.padEnd(7, '0'));   // 1230000

4. ES9 (ECMAScript 2018): 异步迭代的引入 citeturn8view2

4.1 异步迭代 (async iterators)

const asyncIterable = {
  [Symbol.asyncIterator]() {
    return { next: () => Promise.resolve({ done: false, value: 1 }) };
  },
};
console.log(asyncIterable);

4.2 trimLeft / trimRight

const str1 = '   hello world   ';
console.log(str1.trimLeft());

const str2 = '   hello world   ';
console.log(str2.trimRight());

5. ES10 (ECMAScript 2019): 数组和字符串的增强 citeturn8view2turn8view3

5.1 flat / flatMap

const arr = [1, [2, [3, [4]]]];
console.log(arr.flat(2)); // [1,2,3,[4]]

const deepArr = [1, [2, [3, [4, [5]]]]];
console.log(deepArr.flat(4)); // [1,2,3,4,5]

5.2 Array.prototype.flatMap() citeturn8view3

const numbers = [[1, 2], [3, 4], [5, 6]];
const flattened = numbers.flatMap(x => x);
console.log(flattened); // [1,2,3,4,5,6]

5.3 trimStart / trimEnd citeturn8view3

const str1 = '   Hello World   ';
console.log(str1.trimStart());

const str2 = '   Hello World   ';
console.log(str2.trimEnd());

5.4 String.prototype.matchAll citeturn8view3

const str = 'hello world';
const regex = /l/g;
for (const match of str.matchAll(regex)) {
  console.log(match);
}

6. ES11 (ECMAScript 2020): 高级数据操作 citeturn8view3turn9view0

6.1 可选链操作符 (?.)

const obj = { a: { b: null } };
console.log(obj.a?.b?.c); // undefined

6.2 空值合并运算符 (??)

let a = null;
let b = "Hello";
console.log(a ?? b); // "Hello"
console.log(0 ?? b); // 0

6.3 .at() 方法

const arr = ['a', 'b', 'c', 'd'];
console.log(arr.at(-1)); // d
console.log(arr.at(-2)); // c

const str = 'Coding Beauty';
console.log(str.at(-1)); // y

6.4 BigInt 类型

6.4.1 创建 BigInt

const bigIntValue1 = 1234567890123456789012345678901234567890n;
console.log(bigIntValue1, typeof bigIntValue1);

const num = 1234567890123456789012345678901234567890;
const bigIntValue2 = BigInt(num);
console.log(bigIntValue2, typeof bigIntValue2);

6.4.2 BigInt 的基本操作

const a1 = 1234567890123456789012345678901234567890n;
const b1 = 9876543210987654321098765432109876543210n;

console.log(a1 + b1);
console.log(a1 - b1);
console.log(a1 * b1);
console.log(a1 / b1);

6.4.3 注意事项

  • BigInt 不能与 Number 直接混算(需显式转换)
  • BigInt 除法结果仍为 BigInt

6.5 Promise.allSettled

  • 等待所有 Promise 完成(fulfilled 或 rejected),获得更完整的控制

7. ES12 (ECMAScript 2021) citeturn9view0turn9view3

7.1 String.prototype.replaceAll

const str = 'hello world';
console.log(str.replaceAll('l', 'L')); // heLLo worLd

7.2 Promise.any 和 AggregateError

const prom1 = new Promise((resolve) => setTimeout(() => resolve("promise one"), Math.floor(Math.random() * 100)));
const prom2 = new Promise((resolve) => setTimeout(() => resolve("promise two"), Math.floor(Math.random() * 100)));
const prom3 = new Promise((resolve) => setTimeout(() => resolve("promise three"), Math.floor(Math.random() * 100)));

(async function () {
  const result = await Promise.any([prom1, prom2, prom3]);
  console.log(result);
})();

7.3 WeakRef(示例节选)

class Counter {
  constructor(element) {
    this.ref = new WeakRef(element);
    this.start();
  }
  start() {
    if (this.timer) return;
    this.count = 0;
    const tick = () => {
      const element = this.ref.deref();
      if (element) element.textContent = ++this.count;
      else {
        console.log("The element is gone.");
        this.stop();
        this.ref = null;
      }
    };
    tick();
    this.timer = setInterval(tick, 1000);
  }
  stop() {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = 0;
    }
  }
}

7.4 逻辑运算符与赋值表达式 (&&=, ||=, ??=)

let x = 1;
let y = 3;
x &&= y;
x ||= y;
console.log(x, y);

let a2;
let b2 = 2;
a2 ??= b2;
console.log(a2);

7.5 数字分隔符

const number = 1_000_000_000_000;
const binary = 0b1010_0101_1111_1101;
const hex = 0xAF_BF_C3;
console.log(number, binary, hex);

8. ES13 (ECMAScript 2022) citeturn11view1turn11view2turn11view3

8.1 类字段

class Car {
  color = 'blue';
  age = 2;
}

8.3 私有方法和字段(#)

class Person {
  #firstName = 'Joseph';
  #lastName = 'Stevens';
  get name() {
    return `${this.#firstName} ${this.#lastName}`;
  }
}

8.4 顶层 await(示例)

function setTimeoutAsync(timeout) {
  return new Promise((resolve) => setTimeout(resolve, timeout));
}
await setTimeoutAsync(3000);

8.5 静态私有字段/方法(示例节选)

class Person {
  static #count = 0;
  static getCount() {
    return this.#count;
  }
  constructor() {
    this.constructor.#incrementCount();
  }
  static #incrementCount() {
    this.#count++;
  }
}

8.6 类静态块

class Vehicle {
  static defaultColor = 'blue';
}
class Car extends Vehicle {
  static colors = [];
  static {
    this.colors.push(super.defaultColor, 'red');
  }
  static {
    this.colors.push('green');
  }
}
console.log(Car.colors);

8.7 检查对象中的私有字段(in)

class Car {
  #color;
  hasColor() {
    return #color in this;
  }
}

8.9 正则表达式匹配索引(/d)

const str = 'sun and moon';
const regex = /and/d;
const matchObj = regex.exec(str);
console.log(matchObj?.indices);

8.10 Object.hasOwn()

const obj = Object.create(null);
obj.color = 'green';
obj.hasOwnProperty = () => false;
console.log(Object.hasOwn(obj, 'color')); // true

8.11 Error cause

try {
  throw new Error('New error message', { cause: new Error('root cause') });
} catch (err) {
  console.log(err.cause);
}

8.12 findLast / findLastIndex(示例节选)

const letters = [{ value: 'v' }, { value: 'w' }, { value: 'x' }, { value: 'y' }, { value: 'z' }];
console.log(letters.findLast((item) => item.value === 'y'));
console.log(letters.findLastIndex((item) => item.value === 'y'));

9. ES14 (ECMAScript 2023) citeturn10view0turn10view1turn10view2

9.1 Array.prototype.toSorted

let arr = [3, 5, 8, 2, 1];
let toSortedArr = arr.toSorted((a, b) => a - b);
console.log(toSortedArr);
console.log(arr); // 原数组不变

9.2 Array.prototype.toReversed

let arr2 = [3, 5, 8, 2, 1];
console.log(arr2.toReversed());
console.log(arr2); // 原数组不变

9.3 Array.prototype.with

const originalArray = [1, 2, 3];
const newArray = originalArray.with(1, 4);
console.log(originalArray);
console.log(newArray);

9.4 Array.prototype.toSpliced

const arr3 = ["red", "orange", "yellow", "green", "blue", "purple"];
const newArr = arr3.toSpliced(2, 1, "pink", "cyan");
console.log(newArr);
console.log(arr3);

9.5 shebang(hashbang)支持

#!/usr/bin/env node

9.6 Symbol 作为 WeakMap 的键(示例节选)

let map = new WeakMap();
const symbolKey = Symbol('uniqueKey');

function useSymbol(symbol) {
  let called = map.get(symbol) || 0;
  map.set(symbol, ++called);
  console.log(`Called: ${called} times`);
}
useSymbol(symbolKey);

10. ES15 (ECMAScript 2024) citeturn10view2turn7view3

10.1 Group By 分组(示例节选)

function myGroupBy(array, iteratee) {
  return array.reduce((groups, value) => {
    const key = iteratee(value);
    if (!groups[key]) groups[key] = [];
    groups[key].push(value);
    return groups;
  }, {});
}

10.2 Math.sign()

  • 正数:1;0:0;-0:-0;NaN:NaN;负数:-1
console.log(Math.sign(2));
console.log(Math.sign(-4));
console.log(Math.sign(0));
console.log(Math.sign(-0));
console.log(Math.sign(NaN));

10.3 Promise.withResolvers(说明+示例节选)

  • 创建 Promise 的同时拿到 resolve/reject
const { promise, resolve, reject } = Promise.withResolvers();
setTimeout(() => resolve("ok"), 1000);
promise.then(console.log);

10.4 正则表达式新标志 /v(Unicode Sets)

  • 提供更强的 Unicode 集合表达能力
  • 支持集合运算(并集、交集、差集)
  • 用于更精确、安全的字符类匹配
// 使用 v 标志的 Unicode 集合(示意)
const regex = /[\p{Script=Greek}&&[^\p{Letter}]]/v;

10.5 ArrayBuffer / SharedArrayBuffer 新能力

  • 改进二进制数据处理能力
  • 更好地支持高性能计算与并发
  • 常用于 WebAssembly、音视频、Worker 场景
const buffer = new ArrayBuffer(16);
const view = new Uint8Array(buffer);
view[0] = 255;

10.6 String.prototype.isWellFormed()

  • 判断字符串是否是合法 UTF-16
  • 用于处理外部输入、跨系统文本
const str = "\uD800"; // 非法 UTF-16
console.log(str.isWellFormed()); // false

10.7 String.prototype.toWellFormed()

  • 将非法 UTF-16 字符替换为 �
  • 常与 isWellFormed 配合使用
const str = "\uD800";
console.log(str.toWellFormed()); // "�"

10.8 Atomics.waitAsync()

  • Atomics.wait 的异步版本
  • 不阻塞主线程
  • 用于并发与 Worker 通信
const sab = new SharedArrayBuffer(4);
const int32 = new Int32Array(sab);

Atomics.waitAsync(int32, 0, 0).value.then(() => {
  console.log("woken up");
});