2025年6月25日,第129届Ecma国际大会批准了ECMAScript 2025语言规范,这标志着它正式成为标准。
📋 目录
- ECMAScript 2025 新增语法指南
✨ ECMAScript 2025 新特性概览
ECMAScript 2025 引入了以下重要特性:
- 导入属性和 JSON 模块 - 原生支持导入 JSON 文件
- 迭代器辅助方法 - 让迭代器操作更加强大
- 新的 Set 方法 - 集合运算的原生支持
- RegExp.escape() - 正则表达式字符串转义
- 正则表达式模式修饰符 - 内联标志支持
- 重复命名捕获组 - 增强的正则表达式功能
- Promise.try() - 简化 Promise 包装
- 16位浮点数支持 - Float16Array 类型
🔧 详细特性介绍
1. 导入属性和 JSON 模块
概述:导入属性为导入非JavaScript资源提供了语法基础。首个支持的格式是JSON模块。
语法:
// 静态导入
import configData from './config.json' with { type: 'json' };
// 动态导入
const userData = await import('./user.json', { with: { type: 'json' } });
// 重新导出
export { settings } from './settings.json' with { type: 'json' };
实际示例:
// config.json
{
"appName": "我的应用",
"version": "1.0.0",
"theme": "dark",
"features": {
"auth": true,
"payment": false
}
}
// app.js
import config from './config.json' with { type: 'json' };
console.log(`应用名称: ${config.appName}`);
console.log(`版本: ${config.version}`);
console.log(`主题: ${config.theme}`);
// 动态加载语言包
async function loadLanguage(lang) {
const translations = await import(`./locales/${lang}.json`, {
with: { type: 'json' }
});
return translations.default;
}
// 使用示例
const zhMessages = await loadLanguage('zh');
console.log(zhMessages.welcome); // "欢迎"
优势:
- 🔒 类型安全:明确指定导入资源类型
- 🚀 性能优化:避免不必要的代码转换
- 🛡️ 安全性增强:防止恶意代码注入
2. 迭代器辅助方法
概述:迭代器辅助方法让我们能够更优雅地处理迭代器,提供类似数组方法的API。
核心方法:
// 返回迭代器的方法
iterator.filter(filterFn) // 过滤
iterator.map(mapFn) // 映射
iterator.flatMap(mapFn) // 扁平化映射
iterator.drop(limit) // 跳过前n个元素
iterator.take(limit) // 取前n个元素
// 返回布尔值的方法
iterator.some(fn) // 是否有任意元素满足条件
iterator.every(fn) // 是否所有元素都满足条件
// 返回其他值的方法
iterator.find(fn) // 查找元素
iterator.reduce(reducer, initialValue?) // 规约
iterator.toArray() // 转换为数组
// 无返回值的方法
iterator.forEach(fn) // 遍历
实际示例:
// 处理用户数据流
const users = [
{ name: '张三', age: 25, department: '技术部' },
{ name: '李四', age: 30, department: '销售部' },
{ name: '王五', age: 35, department: '技术部' },
{ name: '赵六', age: 28, department: '市场部' },
{ name: '钱七', age: 32, department: '技术部' }
];
// 使用迭代器方法链式处理
const techSeniors = users
.values()
.filter(user => user.department === '技术部')
.filter(user => user.age >= 30)
.map(user => ({ ...user, level: 'senior' }))
.take(2)
.toArray();
console.log(techSeniors);
// [
// { name: '王五', age: 35, department: '技术部', level: 'senior' },
// { name: '钱七', age: 32, department: '技术部', level: 'senior' }
// ]
// 处理大数据流(内存友好)
function* generateNumbers(max) {
for (let i = 0; i < max; i++) {
yield i;
}
}
const result = generateNumbers(1000000)
.filter(n => n % 2 === 0) // 只处理偶数
.map(n => n * n) // 平方
.drop(1000) // 跳过前1000个
.take(5) // 只取5个
.toArray();
console.log(result); // [2000000, 2004004, 2008016, 2012036, 2016064]
与数组方法的对比:
// 数组方法(创建中间数组)
const arrayResult = arr
.filter(x => x > 0)
.map(x => x * 2)
.slice(0, 5);
// 迭代器方法(增量计算,内存友好)
const iteratorResult = arr
.values()
.filter(x => x > 0)
.map(x => x * 2)
.take(5)
.toArray();
3. 新的 Set 方法
概述:Set 获得了集合运算的原生支持,提供数学集合理论中的常用操作。
集合运算方法:
// 组合集合
Set.prototype.intersection(other) // 交集
Set.prototype.union(other) // 并集
Set.prototype.difference(other) // 差集
Set.prototype.symmetricDifference(other) // 对称差集
// 检查集合关系
Set.prototype.isSubsetOf(other) // 是否为子集
Set.prototype.isSupersetOf(other) // 是否为超集
Set.prototype.isDisjointFrom(other) // 是否无交集
实际示例:
// 用户权限管理
const adminPermissions = new Set(['read', 'write', 'delete', 'manage']);
const userPermissions = new Set(['read', 'write']);
const guestPermissions = new Set(['read']);
// 检查权限关系
console.log(userPermissions.isSubsetOf(adminPermissions)); // true
console.log(adminPermissions.isSupersetOf(userPermissions)); // true
console.log(userPermissions.isDisjointFrom(guestPermissions)); // false
// 权限操作
const commonPermissions = userPermissions.intersection(guestPermissions);
console.log(commonPermissions); // Set { 'read' }
const allPermissions = adminPermissions.union(userPermissions);
console.log(allPermissions); // Set { 'read', 'write', 'delete', 'manage' }
const extraPermissions = adminPermissions.difference(userPermissions);
console.log(extraPermissions); // Set { 'delete', 'manage' }
// 电商场景:标签管理
const productTags = new Set(['电子产品', '手机', '智能设备']);
const categoryTags = new Set(['手机', '数码', '通讯']);
const sharedTags = productTags.intersection(categoryTags);
console.log(sharedTags); // Set { '手机' }
const uniqueTags = productTags.symmetricDifference(categoryTags);
console.log(uniqueTags); // Set { '电子产品', '智能设备', '数码', '通讯' }
实用工具函数:
// 用户行为分析
function analyzeUserBehavior(activeUsers, premiumUsers, newUsers) {
return {
// 活跃的付费用户
activePremium: activeUsers.intersection(premiumUsers),
// 所有用户
allUsers: activeUsers.union(premiumUsers).union(newUsers),
// 只活跃但未付费的用户
activeNonPremium: activeUsers.difference(premiumUsers),
// 新用户是否都是付费用户
allNewArePremium: newUsers.isSubsetOf(premiumUsers),
// 活跃用户和新用户是否没有重叠
noActiveNewOverlap: activeUsers.isDisjointFrom(newUsers)
};
}
const active = new Set(['user1', 'user2', 'user3']);
const premium = new Set(['user2', 'user4']);
const newUsers = new Set(['user5', 'user6']);
const analysis = analyzeUserBehavior(active, premium, newUsers);
console.log(analysis);
4. RegExp.escape()
概述:RegExp.escape() 用于转义文本,使其可以安全地用在正则表达式中。
语法:
RegExp.escape(string)
实际示例:
// 搜索功能实现
function searchInText(text, searchTerm) {
const escapedTerm = RegExp.escape(searchTerm);
const regex = new RegExp(escapedTerm, 'gi');
return text.match(regex) || [];
}
// 处理特殊字符
const userInput = "What is $price + $tax?";
const matches = searchInText("商品价格: $price + $tax = $total", userInput);
console.log(matches); // ['$price + $tax']
// 文本高亮功能
function highlightText(content, keyword) {
const escapedKeyword = RegExp.escape(keyword);
const regex = new RegExp(`(${escapedKeyword})`, 'gi');
return content.replace(regex, '<mark>$1</mark>');
}
const content = "学习JavaScript很有趣!JavaScript是一门强大的语言。";
const highlighted = highlightText(content, "JavaScript");
console.log(highlighted);
// 学习<mark>JavaScript</mark>很有趣!<mark>JavaScript</mark>是一门强大的语言。
// 移除特定文本(不在引号内)
function removeUnquotedText(str, text) {
const escapedText = RegExp.escape(text);
const regex = new RegExp(`(?<!")${escapedText}(?!")`, 'g');
return str.replace(regex, '•');
}
const sentence = '"yes" and yes and "yes"';
const result = removeUnquotedText(sentence, 'yes');
console.log(result); // '"yes" and • and "yes"'
安全性示例:
// 防止正则表达式注入攻击
function createSearchFilter(userInput) {
// 危险的做法(不要这样做)
// const badRegex = new RegExp(userInput); // 用户可能输入恶意正则表达式
// 安全的做法
const safeRegex = new RegExp(RegExp.escape(userInput));
return safeRegex;
}
// 用户输入包含正则表达式特殊字符
const maliciousInput = "(.*)"; // 这可能导致性能问题
const safeFilter = createSearchFilter(maliciousInput);
console.log(safeFilter.source); // "\\(\\.\\*\\)"
// 文件路径处理
function replaceInPath(path, oldSegment, newSegment) {
const escapedOld = RegExp.escape(oldSegment);
const regex = new RegExp(escapedOld, 'g');
return path.replace(regex, newSegment);
}
const path = "/home/user/docs/file.txt";
const newPath = replaceInPath(path, "/docs/", "/documents/");
console.log(newPath); // "/home/user/documents/file.txt"
5. 正则表达式模式修饰符(内联标志)
概述:正则表达式模式修饰符允许我们将标志应用到正则表达式的特定部分,而不是整个表达式。
语法:
// (?flags:pattern) - 应用标志到特定模式
// 常用标志:
// i - 忽略大小写
// m - 多行模式
// s - 单行模式(. 匹配换行符)
实际示例:
// HTTP请求头解析
const httpHeaders = `
Content-Type: application/json
AUTHORIZATION: Bearer token123
accept: text/html
User-Agent: Mozilla/5.0
`;
// 匹配授权头(忽略大小写)和其他头(区分大小写)
const headerRegex = /^(?i:authorization):\s*(.+)$/gm;
const matches = httpHeaders.match(headerRegex);
console.log(matches); // ['AUTHORIZATION: Bearer token123']
// 混合大小写匹配
const protocolRegex = /^(?i:https?):\/\/(.+)$/;
console.log(protocolRegex.test('HTTP://example.com')); // true
console.log(protocolRegex.test('https://example.com')); // true
// 邮箱验证(域名部分忽略大小写)
const emailRegex = /^[a-z0-9._%+-]+@(?i:[a-z0-9.-]+\.[a-z]{2,})$/;
console.log(emailRegex.test('user@EXAMPLE.COM')); // true
console.log(emailRegex.test('USER@example.com')); // false(用户名部分区分大小写)
// 文档解析(标签名忽略大小写,属性区分大小写)
const xmlRegex = /<(?i:div)\s+class="([^"]*)">/g;
const html = '<DIV class="container"><div class="header">';
const divMatches = [...html.matchAll(xmlRegex)];
console.log(divMatches.map(m => m[1])); // ['container', 'header']
// 日志解析(级别忽略大小写)
const logRegex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} (?i:error|warn|info): (.+)$/;
const logEntries = [
'2025-01-01 10:00:00 ERROR: 系统错误',
'2025-01-01 10:01:00 warn: 警告信息',
'2025-01-01 10:02:00 Info: 一般信息'
];
logEntries.forEach(entry => {
const match = entry.match(logRegex);
if (match) {
console.log(`日志消息: ${match[1]}`);
}
});
复杂示例:
// 多语言代码注释提取
function extractComments(code) {
// 匹配不同语言的注释(语言标识符忽略大小写)
const commentRegex = /\/\*\s*(?i:lang|语言):\s*(\w+)\s*\*\/([\s\S]*?)\/\*/g;
const matches = [...code.matchAll(commentRegex)];
return matches.map(match => ({
language: match[1],
content: match[2].trim()
}));
}
const sourceCode = `
/* LANG: JavaScript */
function hello() {
console.log('Hello World');
}
/**/
/* 语言: Python */
def hello():
print('Hello World')
/**/
`;
const comments = extractComments(sourceCode);
console.log(comments);
// [
// { language: 'JavaScript', content: 'function hello() {\n console.log(\'Hello World\');\n}' },
// { language: 'Python', content: 'def hello():\n print(\'Hello World\')' }
// ]
6. 重复命名捕获组
概述:现在可以在正则表达式的不同分支中使用相同的组名。
语法:
// 在不同的分支中使用相同的组名
/(?<name>pattern1)|(?<name>pattern2)/
实际示例:
// 日期格式解析
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})|(?<day>\d{2})\/(?<month>\d{2})\/(?<year>\d{4})/;
// 解析ISO格式日期
const isoDate = '2025-01-15';
const isoMatch = dateRegex.exec(isoDate);
console.log(isoMatch.groups);
// { year: '2025', month: '01', day: '15' }
// 解析美式格式日期
const usDate = '15/01/2025';
const usMatch = dateRegex.exec(usDate);
console.log(usMatch.groups);
// { year: '2025', month: '01', day: '15' }
// 电话号码格式识别
const phoneRegex = /(?<area>\d{3})-(?<number>\d{4}-\d{4})|(?<area>\d{4})\s(?<number>\d{3}\s\d{4})/;
const cnPhone = '010-1234-5678';
const cnMatch = phoneRegex.exec(cnPhone);
console.log(cnMatch.groups);
// { area: '010', number: '1234-5678' }
const usPhone = '1234 567 8901';
const usMatch = phoneRegex.exec(usPhone);
console.log(usMatch.groups);
// { area: '1234', number: '567 8901' }
// 版本号解析
const versionRegex = /v(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)|(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)/;
function parseVersion(versionString) {
const match = versionRegex.exec(versionString);
if (match) {
return {
major: parseInt(match.groups.major),
minor: parseInt(match.groups.minor),
patch: parseInt(match.groups.patch)
};
}
return null;
}
console.log(parseVersion('v1.2.3')); // { major: 1, minor: 2, patch: 3 }
console.log(parseVersion('2.0.1')); // { major: 2, minor: 0, patch: 1 }
实用工具函数:
// 通用URL解析器
function parseUrl(url) {
const urlRegex = /(?<protocol>https?):\/\/(?<host>[^\/]+)(?<path>\/[^?]*)?(?:\?(?<query>[^#]*))?(?:#(?<fragment>.*))?|(?<protocol>ftp):\/\/(?<host>[^\/]+)(?<path>\/.*)?/;
const match = urlRegex.exec(url);
if (match) {
return {
protocol: match.groups.protocol,
host: match.groups.host,
path: match.groups.path || '/',
query: match.groups.query || '',
fragment: match.groups.fragment || ''
};
}
return null;
}
console.log(parseUrl('https://example.com/path?param=value#section'));
// { protocol: 'https', host: 'example.com', path: '/path', query: 'param=value', fragment: 'section' }
console.log(parseUrl('ftp://files.example.com/downloads/file.zip'));
// { protocol: 'ftp', host: 'files.example.com', path: '/downloads/file.zip', query: '', fragment: '' }
7. Promise.try()
概述:Promise.try() 让我们能够用 Promise 链来处理可能抛出异常的同步代码。
语法:
Promise.try(fn)
实际示例:
// 统一错误处理
function processData(data) {
return Promise.try(() => {
// 这里可能是同步代码,也可能抛出异常
if (!data || typeof data !== 'object') {
throw new Error('无效的数据格式');
}
// 同步处理
const processed = {
id: data.id,
name: data.name?.toUpperCase(),
timestamp: Date.now()
};
// 返回异步操作
return saveToDatabase(processed);
})
.then(result => {
console.log('数据处理成功:', result);
return result;
})
.catch(error => {
console.error('数据处理失败:', error.message);
throw error;
});
}
// 模拟异步数据库操作
function saveToDatabase(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (data.id) {
resolve({ ...data, saved: true });
} else {
reject(new Error('缺少ID字段'));
}
}, 100);
});
}
// 使用示例
processData({ id: 1, name: 'test' })
.then(result => console.log('最终结果:', result))
.catch(error => console.log('处理失败:', error.message));
// 配置加载器
class ConfigLoader {
static load(configPath) {
return Promise.try(() => {
// 同步读取配置(在实际应用中可能是文件读取)
const config = this.readConfigSync(configPath);
// 验证配置
this.validateConfig(config);
// 返回异步的配置处理
return this.processConfig(config);
});
}
static readConfigSync(path) {
// 模拟同步读取配置
const configs = {
'app.json': { name: 'MyApp', version: '1.0.0' },
'invalid.json': null
};
const config = configs[path];
if (!config) {
throw new Error(`配置文件 ${path} 不存在`);
}
return config;
}
static validateConfig(config) {
if (!config.name || !config.version) {
throw new Error('配置文件缺少必要字段');
}
}
static processConfig(config) {
// 模拟异步处理
return new Promise(resolve => {
setTimeout(() => {
resolve({
...config,
loaded: true,
loadTime: new Date().toISOString()
});
}, 50);
});
}
}
// 使用配置加载器
ConfigLoader.load('app.json')
.then(config => console.log('配置加载完成:', config))
.catch(error => console.error('配置加载失败:', error.message));
// API请求包装器
class APIClient {
static request(url, options = {}) {
return Promise.try(() => {
// 同步验证
if (!url) {
throw new Error('URL不能为空');
}
// 同步处理选项
const processedOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
};
// 返回异步请求
return fetch(url, processedOptions);
})
.then(response => {
if (!response.ok) {
throw new Error(`HTTP错误: ${response.status}`);
}
return response.json();
});
}
}
// 使用API客户端
APIClient.request('https://api.example.com/data')
.then(data => console.log('API响应:', data))
.catch(error => console.error('API请求失败:', error.message));
8. 16位浮点数支持(float16)
概述:添加了对16位浮点数的支持,包括 Float16Array 和相关的 DataView 方法。
新增API:
// 新的数学方法
Math.f16round(value)
// 新的类型化数组
new Float16Array(length)
new Float16Array(array)
new Float16Array(buffer, byteOffset?, length?)
// DataView 方法
DataView.prototype.getFloat16(byteOffset, littleEndian?)
DataView.prototype.setFloat16(byteOffset, value, littleEndian?)
实际示例:
// 创建16位浮点数数组
const float16Array = new Float16Array(5);
float16Array[0] = 3.14159;
float16Array[1] = 2.71828;
float16Array[2] = 1.41421;
float16Array[3] = 0.57721;
float16Array[4] = 1.61803;
console.log(float16Array);
// Float16Array [3.140625, 2.71875, 1.4140625, 0.57763671875, 1.6171875]
// 精度比较
const float32Array = new Float32Array(float16Array);
const float64Array = new Float64Array(float16Array);
console.log('Float16精度:', float16Array[0]); // 3.140625
console.log('Float32精度:', float32Array[0]); // 3.140625
console.log('Float64精度:', float64Array[0]); // 3.140625
// Math.f16round 使用
console.log(Math.f16round(3.14159)); // 3.140625
console.log(Math.f16round(65536)); // Infinity (超出范围)
// 图形处理应用
class Color16 {
constructor(r, g, b, a = 1.0) {
this.values = new Float16Array(4);
this.values[0] = r;
this.values[1] = g;
this.values[2] = b;
this.values[3] = a;
}
get r() { return this.values[0]; }
get g() { return this.values[1]; }
get b() { return this.values[2]; }
get a() { return this.values[3]; }
set r(value) { this.values[0] = Math.f16round(value); }
set g(value) { this.values[1] = Math.f16round(value); }
set b(value) { this.values[2] = Math.f16round(value); }
set a(value) { this.values[3] = Math.f16round(value); }
toArray() {
return Array.from(this.values);
}
}
const color = new Color16(0.8, 0.6, 0.4, 1.0);
console.log('颜色值:', color.toArray());
// 内存使用比较
const largeFloat32Array = new Float32Array(1000000);
const largeFloat16Array = new Float16Array(1000000);
console.log('Float32数组大小:', largeFloat32Array.byteLength, '字节');
console.log('Float16数组大小:', largeFloat16Array.byteLength, '字节');
console.log('内存节省:',
`${((largeFloat32Array.byteLength - largeFloat16Array.byteLength) / largeFloat32Array.byteLength * 100).toFixed(1)}%`
);
// DataView 操作
const buffer = new ArrayBuffer(8);
const dataView = new DataView(buffer);
// 写入16位浮点数
dataView.setFloat16(0, 3.14159, true); // 小端序
dataView.setFloat16(2, 2.71828, true);
// 读取16位浮点数
const value1 = dataView.getFloat16(0, true);
const value2 = dataView.getFloat16(2, true);
console.log('读取的值:', value1, value2);
// 机器学习权重存储
class NeuralNetworkWeights {
constructor(weights) {
this.weights = new Float16Array(weights);
}
getLayer(start, size) {
return this.weights.subarray(start, start + size);
}
updateWeights(gradients, learningRate = 0.01) {
for (let i = 0; i < this.weights.length; i++) {
this.weights[i] -= Math.f16round(gradients[i] * learningRate);
}
}
save() {
// 返回更紧凑的权重数据
return {
type: 'float16',
data: Array.from(this.weights),
byteLength: this.weights.byteLength
};
}
}
const weights = new NeuralNetworkWeights([0.1, 0.2, 0.3, 0.4, 0.5]);
console.log('权重数据:', weights.save());
📚 学习资源
官方文档
推荐阅读
- Exploring JavaScript (ES2025 Edition) - Dr. Axel Rauschmayer
- ECMAScript 功能兼容性表
实践资源
🎯 总结
ECMAScript 2025 带来了许多令人兴奋的新特性:
🔥 最实用的特性
- JSON 模块导入 - 简化配置管理
- 迭代器辅助方法 - 强化数据处理能力
- Promise.try() - 统一同步/异步错误处理
🚀 性能优化
- Float16Array - 节省内存,适合图形处理
- 迭代器方法 - 增量计算,减少内存占用
🛡️ 安全性增强
- RegExp.escape() - 防止正则表达式注入
- 导入属性 - 明确指定资源类型
🔧 开发体验改善
- Set 方法 - 原生集合运算
- 正则表达式增强 - 更灵活的模式匹配
这些新特性将显著提升 JavaScript 的表达能力和开发效率,让我们能够编写更清晰、更安全、更高效的代码。
感谢 ECMAScript 2025 编辑团队的杰出工作,以及整个 JavaScript 社区的贡献!
基于: ECMAScript 2025 官方规范
参考资料: 2ality.com