在过去一年里,JavaScript 经历了一场静悄悄的革命:Signal 正式进入标准化进程,Temporal 终于落地,显式资源管理、精确数学运算、JSON 源文本访问……一大批困扰开发者多年的“顽疾”正在被根治。
今天,我们就以 Signal 为核心,串联起 2026 年 JavaScript 最重要的新特性,看看这门“最被低估的语言”正在如何重塑自己。
一、🎯 什么是 Signal?一个等了十年的“响应式原语”
1.1 从“拉”到“推”的范式革命
要理解 Signal,我们先得回到前端开发的本质:状态 → UI。
在传统 MVC 模式中,UI 是状态的纯函数——给定相同状态,永远得到相同 UI。这被称为 “拉取(Pull)”模式:每次状态变化,你都得手动“拉”一遍新 UI 。
// Pull 模式的痛点
let counter = 1;
let isEven = counter % 2 === 0; // 需要手动计算
counter = 2;
// isEven 还是 false!忘更新了
随着应用变复杂,这种手动同步方式必然导致 bug。于是框架们开始探索 “推送(Push)”模式:状态变化时,自动“推”给所有依赖者。这就是 Signal 的核心思想 。
1.2 Signal 是什么?
Signal 是“响应式变量”的标准实现。它让你声明一个值,然后所有基于它的计算都会自动更新 。
javascript
//NodeJS: npx jsr add @patrickjs/signals
import { Signal } from '@patrickjs/signals';
const counter = new Signal.State(0);
const isEven = new Signal.Computed(() => (counter.get() & 1) === 0);
const parity = new Signal.Computed(() => isEven.get() ? '偶数' : '奇数');
console.log(parity.get()); // "偶数"
counter.set(1); // 自动触发所有依赖更新
console.log(parity.get()); // "奇数"
看懂了吗?你只声明了 counter,isEven 和 parity 会自动跟踪并更新——零手动维护,零 bug 隐患 。
二、🧩 Signal 提案深度解析
2.1 提案背景:为什么需要标准?
目前,每个框架都有自己的响应式实现:
- Vue:
ref/reactive - Solid:
createSignal - Angular:
signal() - Preact:
@preact/signals
它们概念相似但 API 不同,导致跨框架复用逻辑几乎不可能。TC39 的 Signal 提案正是为了解决这个问题:定义一个语言层面的标准响应式原语,让所有框架可以互通 。
提案作者阵容堪称“复仇者联盟”:
2.2 核心 API 设计
Signal.State:可变的信号源
javascript
const count = new Signal.State(0);
count.get(); // 读取
count.set(5); // 更新
Signal.Computed:基于其他信号的推导
javascript
const firstName = new Signal.State("张");
const lastName = new Signal.State("三");
const fullName = new Signal.Computed(
() => `${firstName.get()} ${lastName.get()}`
);
Signal.subtle.Watcher:底层观察者(给框架作者用)
javascript
const watcher = new Signal.subtle.Watcher(() => {
// 当任何被 watch 的信号变“脏”时触发
for (const s of watcher.getPending()) {
s.get(); // 重新计算
}
});
watcher.watch(computedSignal);
注意:提案不包含 effect、DOM 更新、批处理等上层 API——这些留给框架实现。这种“最小核心”设计让 Signal 足够灵活,又能保证互操作性 。
2.3 为什么 React 不用 Signal?
这是个敏感但必须谈的话题。React 坚持 “拉取”模式:每次状态变化都重新执行整个组件函数,通过虚拟 DOM 计算差异 。
Signal 是 “推送”模式:状态变化时,只更新依赖它的具体部分。
两种范式没有绝对优劣:
- React 方式:更可预测,调试简单,适合复杂 UI 树
- Signal 方式:性能更高,适合细粒度响应场景
有趣的是,React 团队并未完全拒绝 Signal——如果提案标准化,React 完全可以在底层用 Signal 实现 useState,上层 API 保持不变 。
三、🚀 2026 年其他重磅特性:Signal 不是一个人在战斗
Signal 固然耀眼,但 ES2026 的其他新特性同样值得关注。
3.1 ✅ 已进入 Stage 4 的特性(确定纳入 ES2026)
Temporal API:Date 的“终极替代者”
历经近 10 年,Temporal 终于在 2026 年 3 月达到 Stage 4,正式成为语言规范的一部分 。
javascript
// 终于不用忍受 Date 的魔幻行为了!
const now = Temporal.Now.instant();
const birthday = Temporal.PlainDate.from('2026-03-17');
const zoned = Temporal.ZonedDateTime.from({
timeZone: 'Asia/Shanghai',
year: 2026,
month: 3,
day: 17
});
Temporal 解决了 Date 的所有痛点:
Math.sumPrecise:精确求和
// 以前:0.1 + 0.2 = 0.30000000000000004
// 现在:
Math.sumPrecise([0.1, 0.2]); // 0.3
Uint8Array 转 Base64
javascript
const bytes = new Uint8Array([104, 101, 108, 108, 111]);
const b64 = bytes.toBase64(); // "aGVsbG8="
const back = Uint8Array.fromBase64(b64);
JSON.parse 源文本访问
const result = JSON.parse('{"big": 999999999999999999}', {
sourceText: (key, value, source) => {
if (key === 'big') return BigInt(source);
return value;
}
});
Error.isError
// 比 instanceof 更可靠(跨 iframe、跨 realm)
if (Error.isError(something)) {
// 真的是 Error 对象
}
Iterator.concat
const iter1 = [1, 2].values();
const iter2 = [3, 4].values();
const combined = Iterator.concat(iter1, iter2);
[...combined]; // [1, 2, 3, 4]
Intl Locale 增强
获取某地区的“一周第一天”是周几、周末是哪几天——终于不用自己查 CLDR 了 。
3.2 🚧 正在冲刺 Stage 4 的特性
Array.fromAsync
const asyncIter = createAsyncIterable();
const results = await Array.fromAsync(asyncIter);
显式资源管理(using 语法)
js
{
using file = openFile('log.txt');
file.write('hello');
} // 自动 close,即使抛出异常
Import defer(模块懒加载)
// 模块只有在实际使用时才加载
import defer * as hugeModule from './huge.js';
四、💡 Signal 的实际应用场景
说了这么多理论,Signal 到底怎么用?我们看几个真实案例。
4.1 基础计数器
import { signal, computed, effect } from '@preact/signals'; // 现有实现
const count = signal(0);
const double = computed(() => count.value * 2);
effect(() => {
console.log(`Count: ${count.value}, Double: ${double.value}`);
});
// 每 1 秒自增
setInterval(() => count.value++, 1000);
4.2 表单验证(复杂依赖)
const form = {
email: signal(''),
password: signal(''),
confirm: signal('')
};
const emailValid = computed(() =>
form.email.value.includes('@') && form.email.value.includes('.')
);
const passwordsMatch = computed(() =>
form.password.value === form.confirm.value
);
const formValid = computed(() =>
emailValid.value &&
form.password.value.length >= 8 &&
passwordsMatch.value
);
// UI 框架自动订阅这些信号
4.3 跨组件共享状态
// store.js
export const user = signal(null);
export const posts = computed(() =>
user.value ? fetchPosts(user.value.id) : []
);
// ComponentA.js
import { user } from './store';
user.value = { id: 1, name: '张三' }; // 所有依赖自动更新
// ComponentB.js
import { posts } from './store';
// posts 会自动更新!
五、🔮 未来展望:Signal 之后是什么?
5.1 时间线预测
5.2 可能的影响
- 框架层变薄:响应式核心由引擎提供,框架只需关注渲染
- 跨框架组件:基于标准 Signal 的组件库可在任何框架运行
- 性能提升:引擎可深度优化 Signal 实现(比如 Rust 重写核心)
5.3 你现在可以做什么?
- 学习现有 Signal 实现(Preact Signals、Solid)
- 关注 TC39 提案仓库:
github.com/tc39/proposal-signals - 试用 polyfill:
jsr:@patrickjs/signals
六、📝 总结:2026,JavaScript 的“成人礼”
如果说 ES6 让 JavaScript 成为“真正的语言”,那 2026 年就是它走向“成熟语言”的里程碑:
- Signal:统一响应式编程模型
- Temporal:终结日期处理的噩梦
- 显式资源管理:让代码更健壮
- 精确数学:不再为浮点 bug 抓狂
- JSON 源文本:解决大数精度
这些特性不是简单的语法糖,而是对语言底层能力的系统性补全。它们让 JavaScript 不仅能“写出来”,更能“写好”——写出更健壮、更可维护、更高性能的代码。