📅 整理时间:2026 年 3 月 | 数据来源:TC39 官方提案、MDN、Ecma International、Can I Use
从 ES5 到 ES2026,JavaScript 走过了超过十五年的现代化演进。本文系统盘点每个版本的核心新特性,标注 Chrome 兼容性,并深入探讨当前正在 TC39 审核流程中的下一代功能。
兼容性说明:
🟢 Chrome XX+表示该特性从对应 Chrome 版本起完整支持;🔜 实验中表示已有实验性实现但尚未默认开启;⏳ 暂未支持表示截至 2026 年 3 月尚无稳定实现。
目录
- ES5(2009)— 现代 JS 的基石
- ES6 / ES2015 — 革命性的大版本
- ES2016 — 小而精
- ES2017 — 异步时代来临
- ES2018 — 迭代与展开
- ES2019 — 细节打磨
- ES2020 — 现代语法补全
- ES2021 — 实用增强
- ES2022 — 类的蜕变
- ES2023 — 不可变操作
- ES2024 — 并发与 Unicode
- ES2025 — 正式发布的新生代
- ES2026 — 即将到来
- 正在审核中:TC39 Stage 3 提案
- 展望 Stage 2:原生 Signals 与框架革命
- 结语:奔跑中的 JavaScript
🏛️ ES5(2009)— 现代 JS 的基石
ES5 是所有现代浏览器的最低公共基准,奠定了"现代 JavaScript"的基础。🟢 Chrome 4+ 全面支持。
| 特性 | 说明 |
|---|---|
"use strict" 严格模式 | 禁止隐式全局变量、禁止 this 隐式绑定为全局 |
Array.isArray() | 可靠地判断数组类型 |
Array.prototype.forEach / map / filter / reduce | 函数式数组操作 |
Object.keys() / values() | 枚举对象属性 |
Object.create() | 原型继承的显式方式 |
Object.defineProperty() | 定义不可枚举/不可写属性,getter/setter |
JSON.parse() / JSON.stringify() | 原生 JSON 支持 |
Function.prototype.bind() | 绑定函数上下文 |
Date.now() | 获取毫秒时间戳 |
| getter / setter 语法 | 对象字面量中使用 get/set |
⚡ ES6 / ES2015 — 革命性的大版本
ES6 是 JavaScript 历史上规模最大的一次更新,引入了 20+ 项重大新特性,彻底改变了前端开发方式。🟢 Chrome 49+ 基本全面支持(模块需 Chrome 61+)。
变量声明 🟢 Chrome 49+
let x = 1; // 块级作用域,可重赋值
const PI = 3.14; // 块级作用域,不可重赋值
箭头函数 🟢 Chrome 45+
const add = (a, b) => a + b;
// 不绑定自身 this,继承外层上下文
模板字符串 🟢 Chrome 41+
const name = 'World';
console.log(`Hello, ${name}!`);
// 支持多行、表达式嵌入
解构赋值 🟢 Chrome 49+
const [a, b] = [1, 2];
const { x, y } = { x: 10, y: 20 };
默认参数 / 剩余参数 / 展开运算符 🟢 Chrome 49+
function greet(name = 'Guest') {} // 默认参数
function sum(...args) {} // 剩余参数
const arr2 = [...arr1, 4, 5]; // 展开运算符
类(Class) 🟢 Chrome 49+
class Animal {
constructor(name) { this.name = name; }
speak() { console.log(`${this.name} makes a noise.`); }
}
class Dog extends Animal {
speak() { console.log(`${this.name} barks.`); }
}
模块(Module) 🟢 Chrome 61+
// 导出
export const PI = 3.14;
export default function add(a, b) { return a + b; }
// 导入
import add, { PI } from './math.js';
Promise 🟢 Chrome 32+
const p = new Promise((resolve, reject) => {
setTimeout(() => resolve('done'), 1000);
});
p.then(v => console.log(v));
Symbol 🟢 Chrome 38+
const id = Symbol('id'); // 唯一标识符,不可枚举
Map / Set / WeakMap / WeakSet 🟢 Chrome 38+
const map = new Map();
map.set('key', 'value');
const set = new Set([1, 2, 3]);
Iterator & Generator 🟢 Chrome 39+
function* gen() {
yield 1;
yield 2;
}
for (const v of gen()) console.log(v);
Proxy & Reflect 🟢 Chrome 49+
const proxy = new Proxy(target, {
get(obj, prop) { return prop in obj ? obj[prop] : 37; }
});
其他特性
| 特性 | Chrome 支持 | 说明 |
|---|---|---|
for...of 循环 | 🟢 38+ | 遍历可迭代对象 |
Object.assign() | 🟢 45+ | 浅拷贝/合并对象 |
Number.isInteger() / Number.isNaN() | 🟢 34+ | 更严格的数字判断 |
Array.from() | 🟢 45+ | 将类数组/可迭代对象转为数组 |
String.includes() / startsWith() / endsWith() | 🟢 41+ | 字符串包含检测 |
计算属性名 [expr] | 🟢 47+ | 对象字面量支持动态属性名 |
| 尾调用优化 | 部分支持 | 特定尾调用场景的栈优化(严格模式) |
🔹 ES2016(ES7)— 小而精
ES2016 只引入了两项新特性:
| 特性 | Chrome 支持 | 说明 | 示例 |
|---|---|---|---|
Array.prototype.includes() | 🟢 47+ | 判断数组是否包含某值,支持 NaN 检测 | [1,2,NaN].includes(NaN) // true |
幂运算符 ** | 🟢 52+ | 指数运算的语法糖 | 2 ** 10 // 1024 |
🔹 ES2017(ES8)— 异步时代来临
async / await 🟢 Chrome 55+
async function fetchData() {
try {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return data;
} catch (e) {
console.error(e);
}
}
Object 新方法 🟢 Chrome 54+
Object.values({ a: 1, b: 2 }); // [1, 2]
Object.entries({ a: 1, b: 2 }); // [['a', 1], ['b', 2]]
Object.getOwnPropertyDescriptors(obj); // 获取全部属性描述符
String 补全 🟢 Chrome 57+
'5'.padStart(3, '0'); // '005'
'hi'.padEnd(5, '!'); // 'hi!!!'
SharedArrayBuffer 和 Atomics 🟢 Chrome 68+(受限)
支持多线程 Worker 之间共享内存和原子操作。因 Spectre 漏洞曾短暂撤回,现需跨域隔离头部(COOP/COEP)才可启用。
🔹 ES2018(ES9)— 迭代与展开
异步迭代(Async Iteration) 🟢 Chrome 63+
async function* asyncGenerator() {
yield 1; yield 2;
}
for await (const val of asyncGenerator()) {
console.log(val);
}
Rest/Spread 对象展开 🟢 Chrome 60+
const { a, ...rest } = { a: 1, b: 2, c: 3 };
// rest = { b: 2, c: 3 }
const merged = { ...obj1, ...obj2 };
Promise.prototype.finally() 🟢 Chrome 63+
fetch('/api')
.then(res => res.json())
.catch(err => console.error(err))
.finally(() => hideLoading()); // 无论成败都执行
正则增强 🟢 Chrome 62–64+
| 特性 | Chrome 支持 | 说明 |
|---|---|---|
命名捕获组 (?<name>...) | 🟢 64+ | 通过名字引用捕获组 |
lookbehind 断言 (?<=...) | 🟢 62+ | 向后查找 |
Unicode 属性转义 \p{...} | 🟢 64+ | Unicode 分类匹配 |
dotAll 模式标志 s | 🟢 62+ | . 匹配包括换行符的所有字符 |
🔹 ES2019(ES10)— 细节打磨
| 特性 | Chrome 支持 | 说明 | 示例 |
|---|---|---|---|
Array.prototype.flat() | 🟢 69+ | 数组扁平化 | [1,[2,[3]]].flat(2) |
Array.prototype.flatMap() | 🟢 69+ | map 后 flat 一层 | arr.flatMap(x => [x, x*2]) |
Object.fromEntries() | 🟢 73+ | entries 数组转对象 | Object.fromEntries(map) |
String.prototype.trimStart/trimEnd() | 🟢 66+ | 去除首/尾空格 | ' hi '.trimStart() |
| 可选 catch 绑定 | 🟢 66+ | catch 可省略 (e) | try {} catch {} |
Array.prototype.sort 稳定排序 | 🟢 70+ | 规范要求稳定排序 | — |
Symbol.prototype.description | 🟢 70+ | 访问 Symbol 描述 | sym.description |
| JSON 超集 | 🟢 66+ | JSON 可包含 U+2028/2029 行分隔符 | — |
🔹 ES2020(ES11)— 现代语法补全
可选链 ?. 🟢 Chrome 80+
const city = user?.address?.city; // 不报错,返回 undefined
const fn = obj?.method?.(); // 可选方法调用
空值合并 ?? 🟢 Chrome 80+
const name = user.name ?? '匿名'; // 只有 null/undefined 时才取默认值
// 区别于 || 会把 0、'' 也当 falsy
BigInt 🟢 Chrome 67+
const big = 9007199254740991n + 1n; // 超过 Number 精度的整数
typeof big === 'bigint'
Promise.allSettled() 🟢 Chrome 76+
// 等待所有 Promise 完成,无论成功失败
const results = await Promise.allSettled([p1, p2, p3]);
results.forEach(r => console.log(r.status, r.value ?? r.reason));
globalThis 🟢 Chrome 71+
// 统一访问全局对象(浏览器=window, Node=global, Worker=self)
globalThis.setTimeout(() => {}, 0);
其他特性
| 特性 | Chrome 支持 | 说明 |
|---|---|---|
String.prototype.matchAll() | 🟢 73+ | 正则全局匹配,返回迭代器 |
动态 import() | 🟢 63+ | 按需加载模块 |
import.meta | 🟢 64+ | 访问模块元信息(URL 等) |
🔹 ES2021(ES12)— 实用增强
| 特性 | Chrome 支持 | 说明 | 示例 |
|---|---|---|---|
String.prototype.replaceAll() | 🟢 85+ | 替换所有匹配 | str.replaceAll('a', 'b') |
Promise.any() | 🟢 85+ | 任意一个成功就 resolve | await Promise.any([p1,p2]) |
| 逻辑赋值运算符 | 🟢 85+ | 条件赋值语法糖 | a ||= b; a &&= b; a ??= b |
数字分隔符 _ | 🟢 75+ | 提升大数字可读性 | 1_000_000 / 0xFF_FF |
WeakRef | 🟢 84+ | 弱引用对象,不阻止 GC | new WeakRef(target) |
FinalizationRegistry | 🟢 84+ | 对象被 GC 后的回调 | new FinalizationRegistry(fn) |
🔹 ES2022(ES13)— 类的蜕变
类字段全面增强 🟢 Chrome 94+
class Counter {
// 公共实例字段
count = 0;
// 私有字段
#secret = 42;
// 静态公共字段
static version = '1.0';
// 静态私有字段
static #instances = 0;
// 私有方法
#increment() { this.count++; }
// 静态初始化块
static {
Counter.#instances = 0;
console.log('Class initialized');
}
}
私有字段 in 检查 🟢 Chrome 91+
class MyClass {
#value = 42;
static hasValue(obj) {
return #value in obj; // 品牌检查,不报错
}
}
顶层 await 🟢 Chrome 89+
// 模块顶层直接使用 await(无需包裹 async 函数)
const data = await fetch('/api').then(r => r.json());
export { data };
其他特性
| 特性 | Chrome 支持 | 说明 |
|---|---|---|
Array.prototype.at() | 🟢 92+ | 支持负索引访问 arr.at(-1) |
String.prototype.at() | 🟢 92+ | 字符串负索引 |
Object.hasOwn() | 🟢 93+ | 更安全的 hasOwnProperty 替代 |
Error cause | 🟢 93+ | new Error('msg', { cause: err }) |
RegExp Match Indices(d 标志) | 🟢 90+ | 返回捕获组的开始/结束位置 |
🔹 ES2023(ES14)— 不可变操作
从末尾查找 🟢 Chrome 97+
[1, 2, 3, 4].findLast(x => x % 2 === 0); // 4
[1, 2, 3, 4].findLastIndex(x => x % 2 === 0); // 3
非破坏性数组方法(Change Array by Copy) 🟢 Chrome 110+
const arr = [3, 1, 2];
arr.toSorted(); // [1, 2, 3] 原数组不变
arr.toReversed(); // [2, 1, 3] 原数组不变
arr.toSpliced(1, 1, 9); // [3, 9, 2] 原数组不变
arr.with(1, 99); // [3, 99, 2] 替换指定索引,原数组不变
Symbol 作为 WeakMap 键 🟢 Chrome 108+
const key = Symbol('key');
const wm = new WeakMap();
wm.set(key, { data: 'value' }); // 允许 Symbol 作为键
#! Hashbang 语法 🟢 Chrome 74+
#!/usr/bin/env node
// Node.js 脚本的 shebang 行,正式纳入语法规范
🔹 ES2024(ES15)— 并发与 Unicode
Promise.withResolvers() 🟢 Chrome 119+
// 将 resolve/reject 暴露到 Promise 外部,极大简化事件驱动场景
const { promise, resolve, reject } = Promise.withResolvers();
setTimeout(() => resolve('done'), 1000);
await promise;
数组 / 对象分组 🟢 Chrome 117+
const inventory = [
{ name: 'apple', type: 'fruit' },
{ name: 'banana', type: 'fruit' },
{ name: 'carrot', type: 'vegetable' },
];
Object.groupBy(inventory, item => item.type);
// { fruit: [...], vegetable: [...] }
Map.groupBy(inventory, item => item.type);
// Map { 'fruit' => [...], 'vegetable' => [...] }
ArrayBuffer 增强 🟢 Chrome 114+
// 可调整大小的 ArrayBuffer
const buf = new ArrayBuffer(8, { maxByteLength: 16 });
buf.resize(12);
// ArrayBuffer.prototype.transfer() — 零拷贝转移所有权
const newBuf = buf.transfer();
正则表达式 v 标志(集合表示法) 🟢 Chrome 112+
// 更强大的 Unicode 集合运算
/[\p{Script_Extensions=Greek}&&\p{Letter}]/v
/[A-Z--Q]/v // 差集:A-Z 中排除 Q
Atomics.waitAsync() 🟢 Chrome 87+
// 异步等待 SharedArrayBuffer 上的条件(主线程可用)
const result = await Atomics.waitAsync(sharedArray, 0, 0).value;
String.prototype.isWellFormed() / toWellFormed() 🟢 Chrome 111+
'\uD800'.isWellFormed(); // false(孤立代理项)
'\uD800'.toWellFormed(); // 替换为 U+FFFD
🔹 ES2025(ES16)— 正式发布的新生代
✅ 已于 2025 年 6 月 25 日由 Ecma 大会第 129 次会议正式批准
新 Set 方法 🟢 Chrome 122+
const a = new Set([1, 2, 3, 4]);
const b = new Set([3, 4, 5, 6]);
a.union(b); // {1, 2, 3, 4, 5, 6} 并集
a.intersection(b); // {3, 4} 交集
a.difference(b); // {1, 2} 差集
a.symmetricDifference(b); // {1, 2, 5, 6} 对称差集
a.isSubsetOf(b); // false
a.isSupersetOf(b); // false
a.isDisjointFrom(b); // false
Promise.try() 🟢 Chrome 130+
// 统一包装同步或异步函数,始终返回 Promise
// 无需再区分 try/catch 与 .catch()
Promise.try(() => JSON.parse(userInput))
.then(data => process(data))
.catch(err => handleError(err));
迭代器辅助方法(Iterator Helpers) 🟢 Chrome 122+
function* range(start, end) {
for (let i = start; i < end; i++) yield i;
}
Iterator.from(range(0, 10))
.filter(n => n % 2 === 0)
.map(n => n ** 2)
.take(3)
.toArray(); // [0, 4, 16]
// 支持的方法:map / filter / take / drop / flatMap / forEach / reduce / toArray / find / every / some
JSON Modules & Import Attributes 🟢 Chrome 123+
// 直接导入 JSON 文件(with 语法)
import config from './config.json' with { type: 'json' };
正则表达式修饰符(Inline Flags) 🟢 Chrome 125+
// (?flags:pattern) — 局部启用/禁用标志
const re = /^[a-z](?-i:[a-z])[a-z]$/i;
// 整体不区分大小写,中间那个字符区分大小写
重复命名捕获组 🟢 Chrome 125+
// 不同分支可复用同一捕获组名
const re = /(?:(?<year>\d{4})-\d{2}|\d{2}-(?<year>\d{4}))/;
Float16Array 🟢 Chrome 130+
// 16位半精度浮点数,适用于 ML/GPU 计算、WebGL、WebGPU
const f16 = new Float16Array([1.5, 2.5, 3.5]);
Math.f16round(1.337); // 转换为最近的 float16 值
const dv = new DataView(buf);
dv.getFloat16(0); // 读取 float16
dv.setFloat16(0, 3.14); // 写入 float16
RegExp.escape() 🟢 Chrome 134+
// 转义字符串中的所有正则特殊字符,安全构造动态正则
const userInput = 'hello.world+test';
new RegExp(RegExp.escape(userInput)); // 等价于 /hello\.world\+test/
🔹 ES2026(ES17)— 即将到来
📌 预计 2026 年 6 月正式发布,以下特性多数已进入 Stage 4
🗓️ Temporal API — 彻底重写日期时间 🔜 Chrome 127+ 实验性
内置 Date 对象的替代品,解决几十年来的历史遗留问题:
// 当前时刻(含时区)
const now = Temporal.Now.zonedDateTimeISO('Asia/Shanghai');
// 创建特定日期
const date = Temporal.PlainDate.from('2026-06-15');
// 时间加减(不可变,返回新对象)
const nextWeek = date.add({ days: 7 });
// 时区转换
const tokyo = now.withTimeZone('Asia/Tokyo');
// 日期差值
const diff = date1.until(date2, { largestUnit: 'days' });
// 支持非格里历(如农历)
const lunar = Temporal.PlainDate.from({
calendar: 'chinese', year: 4722, month: 1, day: 1
});
Temporal 的核心优势:
- 不可变对象(Immutable),避免意外修改
- 明确区分
PlainDate/ZonedDateTime/Instant等类型 - 内置时区和日历系统(含农历等非格里历)
- 与
Intl无缝集成,国际化开箱即用
➕ Math.sumPrecise() 🔜 实验中
// 传统方法的精度问题
[0.1, 0.2, 0.3].reduce((a, b) => a + b, 0); // 0.6000000000000001
// 精确求和(使用 Neumaier 算法等减少浮点误差)
Math.sumPrecise([0.1, 0.2, 0.3]); // 0.6
❓ Error.isError() 🟢 Chrome 123+
// 跨 Realm 可靠检测 Error(iframe、Worker、扩展等场景)
Error.isError(new Error('oops')); // true
Error.isError(new TypeError('bad type')); // true
Error.isError({ message: 'fake error' }); // false
// 比 instanceof Error 更可靠,不受跨 iframe 原型链断裂影响
🔑 Map Upsert 🟢 Chrome 131+
// getOrInsert:存在则获取,不存在则插入
const cache = new Map();
const val = cache.getOrInsert('key', defaultValue);
// getOrInsertComputed:惰性计算插入值(避免不必要的计算)
const val2 = cache.getOrInsertComputed('key', key => computeExpensive(key));
📦 Uint8Array ↔ Base64 / Hex 🟢 Chrome 132+
// 二进制 ↔ Base64(告别 btoa/atob 的混乱)
const bytes = new Uint8Array([72, 101, 108, 108, 111]);
const base64 = bytes.toBase64(); // 'SGVsbG8='
Uint8Array.fromBase64('SGVsbG8='); // Uint8Array [72, 101, 108, 108, 111]
// 二进制 ↔ Hex
bytes.toHex(); // '48656c6c6f'
Uint8Array.fromHex('48656c6c6f'); // Uint8Array [72, 101, 108, 108, 111]
🔗 Iterator.concat() ⏳ 暂未稳定支持
// 将多个迭代器顺序连接,无需展开为数组
const combined = Iterator.concat(
[1, 2, 3].values(),
[4, 5, 6].values(),
[7, 8, 9].values()
);
combined.toArray(); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
📝 JSON.parse Source Text Access 🔜 实验中
// 访问 JSON 解析时的原始文本(用于高精度数字等场景)
JSON.parse('{"big": 9007199254740993}', (key, value, context) => {
if (key === 'big') return BigInt(context.source);
return value;
});
🔬 正在审核中:TC39 Stage 3 提案
Stage 3(候选阶段)表示设计已基本冻结,正在等待实现验证,即将进入正式标准。
| 提案 | Chrome 状态 | 说明 | 预期版本 |
|---|---|---|---|
| Decorators | 🔜 实验性(flag) | 类和类成员的装饰器语法,@decorator 注解 | ES2026+ |
| Decorator Metadata | 🔜 实验性(flag) | 为装饰器提供运行时元数据访问 | ES2026+ |
Explicit Resource Management(using) | 🟢 134+ | using conn = getDB() 语句块结束时自动释放资源 | ES2026 |
Deferring Module Evaluation(defer) | 🔜 实验中 | import defer * as ns from './mod.js' 延迟执行 | ES2026 |
| Source Phase Imports | 🔜 实验中 | import source mod from './mod.wasm' 获取原始模块源 | ES2026+ |
| Atomics.pause | 🔜 实验中 | 为自旋锁/忙等待提供 CPU 提示优化 | ES2026 |
| Joint Iteration(Iterator.zip) | ⏳ 暂未支持 | 同步遍历多个迭代器 Iterator.zip([a, b]) | ES2026+ |
| Import Text | 🔜 实验中 | import txt from './file.txt' with { type: 'text' } | ES2026+ |
| Dynamic Code Brand Checks | ⏳ 暂未支持 | 控制 eval/new Function 可执行的代码类型(CSP 增强) | TBD |
| Legacy RegExp features | 🟢 已支持 | 规范遗留正则静态属性(RegExp.input 等) | ES2026+ |
🌱 展望 Stage 2:原生 Signals 与框架革命
这些提案尚在设计或讨论阶段,未来有望推进。其中最值得关注的,是一个可能从根本上重塑前端开发范式的提案——Signals。
⚡ TC39 Signals:响应式编程的语言级统一
提案地址:github.com/tc39/propos…
当前阶段:Stage 1(⏳ 暂无浏览器支持)
背景:框架之争,本质上是响应式之争
过去十年,前端框架的核心竞争力之一就是响应式系统的实现方式:
- Vue 2:基于
Object.defineProperty劫持数据 - Vue 3:基于
Proxy+reactive/ref构建细粒度响应式 - React:
useState+ Fiber 调度,以"重新渲染"换取简单心智模型 - SolidJS:原生 Signal + 细粒度更新,接近零虚拟 DOM 开销
- Angular:Zone.js + 脏检查,近年也引入了 Signals 机制(Angular 16+)
- Preact Signals:独立的 Signal 库,甚至可以跨框架使用
这些实现各有优劣,却彼此割裂——一套 Vue 的响应式状态无法直接在 React 组件中使用,反之亦然。
Signals 提案:统一响应式原语
TC39 Signals 提案由来自 Bloomberg、Google、Ember、MobX、Angular、Vue、SolidJS 等团队的工程师共同推动,目标是为 JavaScript 语言本身引入一套标准化的响应式原语。
核心 API(三件套):
// 1. Signal.State — 可变的响应式数据源
// 对标:Vue 的 ref()、SolidJS 的 createSignal()
const count = new Signal.State(0);
count.get(); // 读取值:0
count.set(1); // 设置值,触发下游更新
// 2. Signal.Computed — 自动追踪依赖的派生状态
// 对标:Vue 的 computed()
// 特性:惰性求值 + 依赖追踪 + 结果缓存
const doubled = new Signal.Computed(() => count.get() * 2);
doubled.get(); // 2(自动依赖 count)
// 3. Signal.subtle.Watcher — 底层副作用调度器
// 对标:React 的 useEffect、Vue 的 watchEffect 的底层
const watcher = new Signal.subtle.Watcher(() => {
// 当依赖变化时被通知,框架在此触发 DOM 更新
});
watcher.watch(doubled);
对 Vue、React 等框架的深远影响
1. 统一的响应式基础,降低学习成本
如果 Signals 进入语言标准,Vue、React、SolidJS 等框架都可以基于同一套原生 Signal 原语构建上层逻辑。开发者学会了原生 Signal,就等于掌握了所有框架响应式系统的底层逻辑——这对于学习曲线的降低意义重大。
2. 跨框架状态共享成为可能
基于原生标准的 Signal,可以在不同框架的组件之间直接共享状态,无需复杂的适配层或第三方状态管理库(如 Zustand、Pinia 等)在跨框架场景下的蹩脚配合。
3. 框架可专注于更高层次的创新
当底层响应式被语言原生承担后,框架团队可以将精力更多投入到渲染优化、组件模型、开发者体验、编译时优化等更高层次的问题,而非在每个框架中重复实现类似的依赖追踪机制。
4. 浏览器 DevTools 原生支持
原生 Signal 使浏览器开发者工具可以内置响应式调试能力——全局信号依赖图谱、信号变化时序追踪等,彻底改变今天各框架只能依赖各自独立 DevTools 扩展的局面。
5. Vue 3 的 ref 与原生 Signal 的关系
Vue 核心团队成员(包括 Evan You 本人)也参与了该提案的讨论。Vue 3 的响应式系统在设计理念上与原生 Signals 高度吻合,这意味着 Vue 未来版本很可能会直接构建在原生 Signal 之上,而非继续维护自己的响应式实现。
6. React 的挑战与机遇
React 的心智模型(单向数据流 + 不可变状态 + 重新渲染)与 Signal 的细粒度订阅更新在哲学上存在差异。但随着 React Compiler(原 React Forget)的推进,React 也在朝着"减少不必要重渲染"的方向演进。原生 Signal 的出现,可能推动 React 生态进行更深层的架构反思,或者催生出与原生 Signal 协同工作的新 Hook 模式。
其他值得关注的 Stage 2 提案
| 提案 | 说明 |
|---|---|
| Type Annotations | 类似 TypeScript 的类型注解语法(仅作为注释,运行时忽略) |
| Pattern Matching | match 表达式,类似 Rust/Haskell 的模式匹配 |
Pipeline Operator |> | 函数链式调用 value |> fn1 |> fn2 |
| Record & Tuple | 不可变的值类型对象/数组(深度相等比较) |
| Throw Expressions | 在表达式位置使用 throw |
| Do Expressions | 块作为表达式 const x = do { ... } |
| Async Context | 类似 Node.js AsyncLocalStorage 的上下文传播 |
| Extractors | 解构赋值中的自定义模式提取 |
📊 版本特性速览总结
| 版本 | 年份 | 重点 | 代表特性 | Chrome 最低要求 |
|---|---|---|---|---|
| ES5 | 2009 | 现代化基础 | 严格模式、JSON、getter/setter | Chrome 4+ |
| ES6 | 2015 | 革命性变革 | let/const、箭头函数、Class、Promise、模块 | Chrome 49+(模块 61+) |
| ES2016 | 2016 | 精简 | includes()、** 运算符 | Chrome 52+ |
| ES2017 | 2017 | 异步 | async/await、Object.entries | Chrome 55+ |
| ES2018 | 2018 | 展开与异步迭代 | for await...of、对象展开、finally | Chrome 63+ |
| ES2019 | 2019 | 细节 | flat/flatMap、Object.fromEntries、可选 catch | Chrome 73+ |
| ES2020 | 2020 | 语法补全 | 可选链 ?.、空值合并 ??、BigInt | Chrome 80+ |
| ES2021 | 2021 | 实用 | replaceAll、逻辑赋值、数字分隔符 | Chrome 85+ |
| ES2022 | 2022 | 类增强 | 私有字段、顶层 await、at() | Chrome 94+ |
| ES2023 | 2023 | 不可变 | toSorted/toReversed、findLast | Chrome 110+ |
| ES2024 | 2024 | 并发/Unicode | Promise.withResolvers、groupBy、正则 v 标志 | Chrome 119+ |
| ES2025 | 2025 | 迭代器/Set | Set 集合运算、迭代器辅助方法、Promise.try | Chrome 130+ |
| ES2026 | 2026 | 日期/精度 | Temporal、Math.sumPrecise、Error.isError | Chrome 131+(部分) |
🚀 结语:奔跑中的 JavaScript
回望这段历史,很难不感叹 JavaScript 演进的速度之快、野心之大。
二十年前,它是一门被人嘲笑的"玩具语言",用来做表单验证和弹窗广告。而今天,它运行在浏览器、服务器(Node.js/Deno/Bun)、移动端(React Native)、桌面端(Electron/Tauri)、边缘计算节点(Cloudflare Workers)、甚至嵌入式设备上——几乎无处不在。
ES6(2015)是第一个分水岭,它用箭头函数、Class、Promise、模块系统彻底重塑了 JavaScript 的开发范式,催生了 React/Vue/Angular 三足鼎立的现代前端时代。
async/await(2017)是第二个分水岭,异步编程从"回调地狱"走向了接近同步代码的优雅写法,Node.js 生态因此爆发式增长。
ES2022 的私有字段、ES2023 的不可变数组方法、ES2024 的 groupBy,则像是一块块精密的拼图,把那些长期依赖 Lodash、underscore 才能做到的事情,一件件纳入了语言本身。
而现在,站在 2026 年的门口,我们正在见证又一次深刻的变革:
- Temporal 的到来,意味着十几年来前端开发者对
Date的每一次抱怨,终于有了官方答案; Math.sumPrecise和Error.isError这类"小而精"的补丁,填补着语言底层的精度与可靠性空白;- 原生 Signals,或许是近十年来最具颠覆性的提案——它不仅仅是一个新 API,而是一场关于前端框架存在意义的深刻追问:当浏览器原生提供了响应式系统,框架还应该做什么?
答案或许是:框架将从"提供响应式"的基础设施角色,进化为更专注于开发者体验、编译优化、组件生态和应用架构的上层抽象。Vue 会更轻,React 会更快,SolidJS 会更标准——每一个框架都将站在更坚实的语言地基上,专注于自己最擅长的那部分。
JavaScript 从未停止奔跑。而每一位前端开发者,都是这场长跑的见证者,也是参与者。
🔗 参考资源
- TC39 官方提案仓库
- TC39 Signals 提案
- ECMAScript 规范(ECMA-262)
- MDN JavaScript 文档
- Can I Use — 浏览器兼容性查询
- Babel Plugin Proposals — 提案转译支持
- The New Stack: ES2026 特性报道
- 掘金:浏览器内置响应式编程?用 TC39 Signals 提案实现 TodoList
💡 提示:TC39 的提案流程分为 Stage 0–4,Stage 4 意味着正式纳入标准。每年 6 月 Ecma 大会批准当年版本。建议通过 github.com/tc39/propos… 实时跟踪最新动态。