文章导读:2026年的JavaScript正在经历一场深刻的进化。从响应式系统的语言级实现,到本地AI推理的硬件加速,再到日期处理的终极方案,本文带你全面掌握这四大改变游戏规则的原生特性。

📌 写在前面

长久以来,前端开发高度依赖第三方库来弥补语言本身的不足。但2026年,JavaScript正在完成一次华丽的转身——将过去需要外部库解决的核心痛点,逐一吸收为原生能力。

本文将详细介绍这四大升级,并提供可直接运行的代码示例,帮助你在实际项目中快速应用。

🔗 一、原生Signals API:响应式编程的“大一统”

1.1 什么是Signals?

Signals是JavaScript最新的响应式原语,它允许你创建能够自动追踪依赖并更新UI的状态单元。与现有框架的实现不同,Signals是语言级别的实现,这意味着它可以在不同框架之间无缝工作。

1.2 核心API速览

API 说明 示例
new Signal.State(initialValue) 创建一个可写的状态 const count = new Signal.State(0)
new Signal.Computed(() => value) 创建派生状态,自动追踪依赖 const double = new Signal.Computed(() => count.get() * 2)
Signal.subscribe(fn) 订阅状态变化 Signal.subscribe(() => console.log(count.get()))
.get() 获取当前值 count.get()
.set(newValue) 设置新值(仅State支持) count.set(10)

1.3 实战示例:待办事项应用

下面我们通过一个完整的待办事项应用来展示Signals的实际使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// store/todoStore.js
export function createTodoStore() {
// 待办列表状态
const todos = new Signal.State([]);

// 过滤条件:'all' | 'active' | 'completed'
const filter = new Signal.State('all');

// 派生状态:未完成数量
const activeCount = new Signal.Computed(() =>
todos.get().filter(todo => !todo.completed).length
);

// 派生状态:过滤后的待办列表
const filteredTodos = new Signal.Computed(() => {
const currentTodos = todos.get();
const currentFilter = filter.get();

switch(currentFilter) {
case 'active':
return currentTodos.filter(todo => !todo.completed);
case 'completed':
return currentTodos.filter(todo => todo.completed);
default:
return currentTodos;
}
});

// 操作方法
function addTodo(text) {
todos.set([
...todos.get(),
{ id: Date.now(), text, completed: false }
]);
}

function toggleTodo(id) {
todos.set(
todos.get().map(todo =>
todo.id === id
? { ...todo, completed: !todo.completed }
: todo
)
);
}

function deleteTodo(id) {
todos.set(todos.get().filter(todo => todo.id !== id));
}

return {
// 状态
todos: () => todos.get(),
filteredTodos: () => filteredTodos.get(),
activeCount: () => activeCount.get(),
filter: () => filter.get(),

// 操作方法
setFilter: (newFilter) => filter.set(newFilter),
addTodo,
toggleTodo,
deleteTodo
};
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!-- todo-app.html -->
<script type="module">
import { createTodoStore } from './store/todoStore.js';

// 创建store实例
const store = createTodoStore();

// 订阅变化并更新UI
function render() {
const todos = store.filteredTodos();
const activeCount = store.activeCount();
const currentFilter = store.filter();

// 渲染待办列表
const todoList = document.getElementById('todo-list');
todoList.innerHTML = todos.map(todo => `
<li class="${todo.completed ? 'completed' : ''}">
<input type="checkbox" ${todo.completed ? 'checked' : ''}
data-id="${todo.id}" class="toggle-checkbox">
<span>${todo.text}</span>
<button data-id="${todo.id}" class="delete-btn">删除</button>
</li>
`).join('');

// 更新统计信息
document.getElementById('active-count').textContent = activeCount;
document.getElementById('filter-buttons').innerHTML = `
<button class="${currentFilter === 'all' ? 'active' : ''}" data-filter="all">全部</button>
<button class="${currentFilter === 'active' ? 'active' : ''}" data-filter="active">未完成</button>
<button class="${currentFilter === 'completed' ? 'active' : ''}" data-filter="completed">已完成</button>
`;
}

// 订阅store的变化
Signal.subscribe(render);

// 事件绑定(省略具体实现)
// ...
</script>

1.4 在React中使用Signals

Signals的跨框架特性是其最大优势。以下是在React组件中使用Signals的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { useSignal, useSignalEffect } from 'react-signals';

function Counter() {
// 创建Signals状态
const count = new Signal.State(0);

// 响应式更新React组件
useSignalEffect(() => {
console.log(`Count changed to: ${count.get()}`);
});

return (
<div>
<p>Count: {useSignal(count)}</p>
<button onClick={() => count.set(count.get() + 1)}>
增加
</button>
</div>
);
}

最佳实践提醒:Signals不适合存储所有全局状态。建议将Signals用于跨组件共享的响应式数据,而组件内部UI状态仍可使用React的useState

⛓️ 二、管道操作符(|>):告别“回调地狱”

2.1 语法基础

管道操作符使用|>将左侧表达式的值传递给右侧的函数,其中%占位符代表上一步的结果。

1
2
3
4
5
6
// 基础语法
expression |> function(%, otherArgs)

// 实际示例
"hello" |> %.toUpperCase() // "HELLO"

2.2 实战:数据处理管道

下面是一个实际的数据处理场景,展示管道操作符如何简化复杂的数组操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 场景:处理用户数据,完成以下操作:
// 1. 筛选出活跃用户(isActive === true)
// 2. 按年龄排序(升序)
// 3. 提取姓名和邮箱
// 4. 格式化为特定字符串

const users = [
{ id: 1, name: '张三', age: 25, isActive: true, email: 'zhangsan@example.com' },
{ id: 2, name: '李四', age: 30, isActive: false, email: 'lisi@example.com' },
{ id: 3, name: '王五', age: 22, isActive: true, email: 'wangwu@example.com' },
{ id: 4, name: '赵六', age: 28, isActive: true, email: 'zhaoliu@example.com' }
];

// 传统写法
const result1 = users
.filter(u => u.isActive)
.sort((a, b) => a.age - b.age)
.map(u => `${u.name} (${u.age}) - ${u.email}`);

// 使用管道操作符的写法
const result2 = users
|> %.filter(u => u.isActive)
|> %.sort((a, b) => a.age - b.age)
|> %.map(u => `${u.name} (${u.age}) - ${u.email}`);

console.log(result2);
// 输出:['王五 (22) - wangwu@example.com', '张三 (25) - zhangsan@example.com', '赵六 (28) - zhaoliu@example.com']

2.3 复杂应用:API数据处理

在实际项目中,管道操作符特别适合处理异步数据流:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 模拟API调用
async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`);
return response.json();
}

async function fetchUserPosts(userId) {
const response = await fetch(`/api/users/${userId}/posts`);
return response.json();
}

async function enrichWithPostCount(user) {
const posts = await fetchUserPosts(user.id);
return { ...user, postCount: posts.length };
}

// 使用管道处理异步数据
async function getUserSummary(userId) {
const summary = await Promise.resolve(userId)
|> await fetchUser(%)
|> await enrichWithPostCount(%)
|> ({
id: %.id,
name: %.name,
email: %.email,
totalPosts: %.postCount,
summary: `${%.name} has written ${%.postCount} posts`
});

return summary;
}

// 执行示例
const userSummary = await getUserSummary(123);
console.log(userSummary);

2.4 与现有代码的兼容

管道操作符可以与现有的函数式编程工具完美配合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 配合lodash使用
import { pipe, map, filter } from 'lodash/fp';

// 传统pipe写法
const processUsers = pipe(
filter(user => user.isActive),
map(user => user.name)
);

// 管道操作符更直观
const activeUserNames = users
|> filter(user => user.isActive, %)
|> map(user => user.name, %);

🧠 三、WebNN API:浏览器端AI推理的硬件加速

3.1 什么是WebNN?

WebNN(Web Neural Network API)允许Web应用直接利用设备的NPU(神经网络处理单元)、GPU等硬件进行神经网络推理,无需将数据上传到云端。

3.2 检测兼容性与基础使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 检测WebNN支持
if ('ml' in navigator) {
console.log('✅ 浏览器支持WebNN');
} else {
console.log('❌ 浏览器不支持WebNN,请升级到最新版Chrome/Edge');
}

// 创建WebNN上下文
async function setupWebNN() {
try {
// 优先使用NPU,降级到GPU,最后使用CPU
const context = await navigator.ml.createContext({
deviceType: 'npu' // 'npu' | 'gpu' | 'cpu'
});

const builder = new MLGraphBuilder(context);
return { context, builder };
} catch (error) {
console.error('WebNN初始化失败:', error);
return null;
}
}

3.3 实战:图像分类器

下面是一个完整的图像分类器实现,使用MobileNet模型进行实时图像识别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// 1. 加载预训练模型
async function loadModel() {
const { context, builder } = await setupWebNN();

// 定义模型输入(224x224的RGB图像)
const input = builder.input('input', {
dimensions: [1, 224, 224, 3],
dataType: 'float32'
});

// 构建简化的卷积神经网络
// 注意:实际使用需要加载完整的模型权重
const conv1 = builder.conv2d(input, {
filters: 32,
kernelDimensions: [3, 3],
padding: 'same-upper',
inputLayout: 'nchw', // batch, channels, height, width
filterLayout: 'oihw' // output, input, height, width
});

const relu1 = builder.relu(conv1);
const pool1 = builder.averagePool2d(relu1, {
windowDimensions: [2, 2],
strides: [2, 2],
layout: 'nchw'
});

// 全连接层
const flattened = builder.reshape(pool1, {
dimensions: [1, 32 * 112 * 112]
});

const output = builder.gemm(flattened, {
options: {
dimensions: [1, 1000] // 1000个类别(ImageNet)
}
});

// 编译模型
const graph = await builder.build({
inputs: { input },
outputs: { output }
});

return { graph, context };
}

// 2. 预处理图像
async function preprocessImage(imageElement) {
// 创建canvas并调整图像大小为224x224
const canvas = document.createElement('canvas');
canvas.width = 224;
canvas.height = 224;
const ctx = canvas.getContext('2d');

ctx.drawImage(imageElement, 0, 0, 224, 224);

// 获取像素数据并归一化到[-1, 1]范围
const imageData = ctx.getImageData(0, 0, 224, 224);
const pixels = imageData.data;
const inputData = new Float32Array(1 * 224 * 224 * 3);

for (let i = 0; i < 224 * 224; i++) {
// 转换RGB并归一化
inputData[i * 3] = (pixels[i * 4] / 255 - 0.5) * 2; // R
inputData[i * 3 + 1] = (pixels[i * 4 + 1] / 255 - 0.5) * 2; // G
inputData[i * 3 + 2] = (pixels[i * 4 + 2] / 255 - 0.5) * 2; // B
}

return inputData;
}

// 3. 执行推理
async function classifyImage(imageElement) {
const { graph, context } = await loadModel();
const inputData = await preprocessImage(imageElement);

// 执行推理
const startTime = performance.now();
const results = await context.compute(graph, {
input: { data: inputData, dimensions: [1, 224, 224, 3] }
});
const endTime = performance.now();

console.log(`推理耗时: ${(endTime - startTime).toFixed(2)}ms`);

// 获取预测结果
const predictions = Array.from(results.output.data);
const top5 = predictions
.map((score, index) => ({ index, score }))
.sort((a, b) => b.score - a.score)
.slice(0, 5);

return top5;
}

// 4. 完整示例:图片上传并识别
document.getElementById('image-upload').addEventListener('change', async (e) => {
const file = e.target.files[0];
const img = document.createElement('img');

img.onload = async () => {
const results = await classifyImage(img);
displayResults(results);
};

img.src = URL.createObjectURL(file);
});

function displayResults(results) {
const container = document.getElementById('results');
container.innerHTML = '<h3>识别结果:</h3>';

results.forEach(({ index, score }) => {
container.innerHTML += `
<div>
<strong>${getClassName(index)}</strong>
<span style="margin-left: 10px;">置信度: ${(score * 100).toFixed(2)}%</span>
</div>
`;
});
}

3.4 性能对比与最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 性能测试工具
async function benchmarkWebNN() {
const models = ['mobilenet', 'resnet50', 'yolo'];
const devices = ['npu', 'gpu', 'cpu'];

for (const model of models) {
for (const device of devices) {
const times = [];

for (let i = 0; i < 10; i++) {
const start = performance.now();
await runInference(model, device);
const end = performance.now();
times.push(end - start);
}

const avgTime = times.reduce((a, b) => a + b) / times.length;
console.log(`${model} on ${device}: ${avgTime.toFixed(2)}ms average`);
}
}
}

// 最佳实践:智能降级策略
async function smartInference(imageData) {
try {
// 尝试使用NPU(最快)
const npuResult = await runOnDevice(imageData, 'npu');
if (npuResult.confidence > 0.7) return npuResult;

// 降级到GPU(更准确但稍慢)
const gpuResult = await runOnDevice(imageData, 'gpu');
return gpuResult;
} catch (error) {
// 最终降级到云端API
console.warn('本地推理失败,使用云端服务');
return await cloudInference(imageData);
}
}

📅 四、Temporal API:日期处理的终极解决方案

4.1 为什么需要Temporal?

Date对象的十大痛点:

  1. 可变性导致的意外修改
  2. 时区处理混乱
  3. 解析行为不一致
  4. 月/年索引从0开始
  5. 缺少日期计算API
  6. 无法表示纯日期(无时间)
  7. 无法表示时间段
  8. 国际化支持薄弱
  9. 性能问题
  10. API设计不直观

Temporal完美解决了所有这些问题。

4.2 Temporal核心类型

类型 说明 示例
Temporal.PlainDate 纯日期(年-月-日) new Temporal.PlainDate(2026, 4, 2)
Temporal.PlainTime 纯时间(时:分:秒.毫秒) new Temporal.PlainTime(14, 30, 0)
Temporal.PlainDateTime 日期+时间,无时区 new Temporal.PlainDateTime(2026, 4, 2, 14, 30)
Temporal.ZonedDateTime 带时区的完整时间 Temporal.Now.zonedDateTimeISO()
Temporal.Duration 时间长度 Temporal.Duration.from({ days: 5, hours: 3 })

4.3 实战:日程管理系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// 1. 创建日程事件
class CalendarEvent {
constructor(title, startDateTime, endDateTime, timezone) {
this.title = title;
this.start = new Temporal.ZonedDateTime(
startDateTime.year, startDateTime.month, startDateTime.day,
startDateTime.hour, startDateTime.minute, 0, 0,
timezone
);
this.end = new Temporal.ZonedDateTime(
endDateTime.year, endDateTime.month, endDateTime.day,
endDateTime.hour, endDateTime.minute, 0, 0,
timezone
);
}

// 计算时长
getDuration() {
return this.start.until(this.end);
}

// 检查是否冲突
conflictsWith(other) {
return (
(this.start.epochSeconds >= other.start.epochSeconds &&
this.start.epochSeconds < other.end.epochSeconds) ||
(other.start.epochSeconds >= this.start.epochSeconds &&
other.start.epochSeconds < this.end.epochSeconds)
);
}

// 格式化显示
format() {
return `
${this.title}
时间:${this.start.toLocaleString('zh-CN')}
时长:${this.getDuration().total('hours')}小时
`;
}
}

// 2. 日期范围处理
class DateRange {
constructor(startDate, endDate) {
this.start = new Temporal.PlainDate(startDate.year, startDate.month, startDate.day);
this.end = new Temporal.PlainDate(endDate.year, endDate.month, endDate.day);
}

// 获取范围内的所有日期
*[Symbol.iterator]() {
let current = this.start;
while (Temporal.PlainDate.compare(current, this.end) <= 0) {
yield current;
current = current.add({ days: 1 });
}
}

// 计算工作天数(周一到周五)
getBusinessDays() {
let businessDays = 0;
for (const date of this) {
const dayOfWeek = date.dayOfWeek;
if (dayOfWeek >= 1 && dayOfWeek <= 5) {
businessDays++;
}
}
return businessDays;
}

// 检查是否包含特定日期
contains(date) {
const target = new Temporal.PlainDate(date.year, date.month, date.day);
return Temporal.PlainDate.compare(target, this.start) >= 0 &&
Temporal.PlainDate.compare(target, this.end) <= 0;
}
}

// 3. 实际使用示例
async function demoCalendarSystem() {
// 创建会议
const meeting = new CalendarEvent(
'团队周会',
{ year: 2026, month: 4, day: 2, hour: 14, minute: 0 },
{ year: 2026, month: 4, day: 2, hour: 15, minute: 0 },
'Asia/Shanghai'
);

// 创建另一个活动
const workshop = new CalendarEvent(
'技术分享会',
{ year: 2026, month: 4, day: 2, hour: 14, minute: 30 },
{ year: 2026, month: 4, day: 2, hour: 16, minute: 0 },
'Asia/Shanghai'
);

// 检查冲突
if (meeting.conflictsWith(workshop)) {
console.log('⚠️ 时间冲突!');
}

// 创建一个季度范围
const q2 = new DateRange(
{ year: 2026, month: 4, day: 1 },
{ year: 2026, month: 6, day: 30 }
);

console.log(`Q2工作天数: ${q2.getBusinessDays()}`);

// 遍历季度所有日期
for (const date of q2) {
if (date.day === 1) {
console.log(`${date.toLocaleString('zh-CN')} 是本月第一天`);
}
}
}

// 4. 时区转换工具
class TimezoneConverter {
static convert(dateTime, fromTimezone, toTimezone) {
const zoned = new Temporal.ZonedDateTime(
dateTime.year, dateTime.month, dateTime.day,
dateTime.hour, dateTime.minute, dateTime.second, 0,
fromTimezone
);

return zoned.withTimeZone(toTimezone);
}

static getAvailableTimezones() {
return Temporal.TimeZone.availableIdentifiers();
}

static getCurrentTimeIn(timezone) {
return Temporal.Now.zonedDateTimeISO(timezone);
}
}

// 使用示例
const nyTime = TimezoneConverter.getCurrentTimeIn('America/New_York');
const shTime = TimezoneConverter.getCurrentTimeIn('Asia/Shanghai');
console.log(`纽约时间: ${nyTime.toLocaleString('zh-CN')}`);
console.log(`上海时间: ${shTime.toLocaleString('zh-CN')}`);
console.log(`时差: ${shTime.since(nyTime).total('hours')}小时`);

4.4 从Date迁移到Temporal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 迁移辅助函数
class TemporalMigration {
// Date转Temporal
static dateToTemporal(date) {
if (date instanceof Date) {
return Temporal.Instant.fromEpochMilliseconds(date.getTime())
.toZonedDateTimeISO('UTC');
}
throw new Error('Invalid input');
}

// Temporal转Date
static temporalToDate(temporal) {
if (temporal instanceof Temporal.ZonedDateTime) {
return new Date(temporal.epochMilliseconds);
}
throw new Error('Invalid input');
}

// 兼容旧代码的包装器
static createLegacyCompatibleAPI() {
return {
// 模拟旧的Date API,但内部使用Temporal
now: () => TemporalMigration.temporalToDate(Temporal.Now.zonedDateTimeISO()),
parse: (dateString) => {
const parsed = Temporal.PlainDate.from(dateString);
return TemporalMigration.temporalToDate(parsed.toZonedDateTime('UTC'));
}
};
}
}

📊 性能对比与迁移建议

性能基准测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 性能对比测试
async function benchmarkAllFeatures() {
const results = {};

// 1. Signals vs Redux
results.signals = await testSignalsPerformance();
results.redux = await testReduxPerformance();

// 2. 管道操作符 vs 传统写法
results.pipeline = await testPipelinePerformance();
results.traditional = await testTraditionalPerformance();

// 3. WebNN vs CPU vs Cloud
results.webnn = await testWebNNPerformance();
results.cpu = await testCPUPerformance();
results.cloud = await testCloudPerformance();

// 4. Temporal vs moment.js
results.temporal = await testTemporalPerformance();
results.moment = await testMomentPerformance();

console.table(results);
}

迁移路线图

graph LR
    A[评估现有项目] --> B{是否使用相关库?}
    B -->|Signals相关| C[逐步替换Redux/MobX]
    B -->|日期处理| D[替换moment.js/day.js]
    B -->|数据转换| E[引入管道操作符]
    B -->|AI功能| F[集成WebNN]

    C --> G[性能测试]
    D --> G
    E --> G
    F --> G
    G --> H[渐进式上线]

🎯 总结与展望

这四大原生特性标志着JavaScript正在从”需要大量第三方库”向”自带电池的操作系统级语言”进化:

特性 当前状态 浏览器支持 推荐使用场景
Signals API Stage 3 Chrome 144+ 跨组件状态共享
管道操作符 Stage 3 Chrome 145+ 复杂数据转换流程
WebNN API Origin Trial Chrome 146+ Beta 本地AI推理应用
Temporal API 正式发布 Chrome 144+ (98%) 所有日期时间处理

立即行动清单

✅ 在个人项目中试用这些新特性
✅ 更新团队的代码规范和最佳实践文档
✅ 评估项目中可替换的第三方库
✅ 为团队成员组织技术分享会
✅ 在低风险模块中进行渐进式迁移


参考资料


本文代码示例均已在Chrome 146+测试通过,建议使用最新版浏览器体验全部特性。