自从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 citeturn8view1
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() citeturn8view1
const arr = Array.of(1, 2, 3);
console.log(arr);
1.12 生成器函数 function*() {} citeturn8view1
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 默认参数和剩余参数 citeturn8view2
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() citeturn8view2
const str = 'abc'.repeat(3);
console.log(str); // abcabcabc
2. ES7 (ECMAScript 2016): 数学运算的提升 citeturn8view2
2.1 指数运算符 (**)
const result = 2 ** 3;
console.log(result); // 8
3. ES8 (ECMAScript 2017): 异步编程的革命 citeturn8view2
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): 异步迭代的引入 citeturn8view2
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): 数组和字符串的增强 citeturn8view2turn8view3
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() citeturn8view3
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 citeturn8view3
const str1 = ' Hello World ';
console.log(str1.trimStart());
const str2 = ' Hello World ';
console.log(str2.trimEnd());
5.4 String.prototype.matchAll citeturn8view3
const str = 'hello world';
const regex = /l/g;
for (const match of str.matchAll(regex)) {
console.log(match);
}
6. ES11 (ECMAScript 2020): 高级数据操作 citeturn8view3turn9view0
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) citeturn9view0turn9view3
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) citeturn11view1turn11view2turn11view3
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) citeturn10view0turn10view1turn10view2
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) citeturn10view2turn7view3
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");
});