JavaScript 2026:Signal 时代来临,语言正在“重新发明”自己

43 阅读6分钟

在过去一年里,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()); // "奇数"

看懂了吗?你只声明了 counterisEven 和 parity 会自动跟踪并更新——零手动维护,零 bug 隐患 


二、🧩 Signal 提案深度解析

2.1 提案背景:为什么需要标准?

目前,每个框架都有自己的响应式实现:

  • Vueref / reactive
  • SolidcreateSignal
  • Angularsignal()
  • Preact@preact/signals

它们概念相似但 API 不同,导致跨框架复用逻辑几乎不可能。TC39 的 Signal 提案正是为了解决这个问题:定义一个语言层面的标准响应式原语,让所有框架可以互通 

提案作者阵容堪称“复仇者联盟”:

  • Rob Eisenberg(Microsoft/Angular)
  • Daniel Ehrenberg(Bloomberg/Igalia)
  • 以及 Vue、Solid、Svelte 的核心成员 

2.2 核心 API 设计

提案目前处于 Stage 1,定义了三个核心原语 

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 的所有痛点:

  • 不可变:所有操作返回新对象
  • 时区内置:不用再拼 moment-timezone
  • 多种类型:区分“时刻”和“日历日期”
  • 4000+ 测试用例,比整个 ES6 的测试还多 

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);

终于不用手写 base64 转换了 

JSON.parse 源文本访问

const result = JSON.parse('{"big": 999999999999999999}', {
  sourceText: (key, value, source) => {
    if (key === 'big') return BigInt(source);
    return value;
  }
});

解决 JSON 大数精度丢失问题 

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,即使抛出异常

类似 C# 的 using,Python 的 with 

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 时间线预测

  • 2026 年:Signal 在 Stage 1-2 细化,polyfill 普及
  • 2027 年:达到 Stage 3,浏览器开始原型实现
  • 2028+ 年:Stage 4,正式进入语言规范 

5.2 可能的影响

  1. 框架层变薄:响应式核心由引擎提供,框架只需关注渲染
  2. 跨框架组件:基于标准 Signal 的组件库可在任何框架运行
  3. 性能提升:引擎可深度优化 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 不仅能“写出来”,更能“写好”——写出更健壮、更可维护、更高性能的代码。