ES9:对象扩展与剩余参数运算符、异步迭代、Promise新增方法、模板字符串修订 相关知识点
ES9(ECMAScript 2018)引入了多项实用特性,主要包括:1)对象展开运算符和剩余参数,支持对象浅拷贝和解构;2)异步迭代功能,通过for await...of实现异步序列遍历,配合异步生成器可处理流式数据;3)Promise新增finally方法用于资源清理;4)修订模板字符串规则,放宽非法转义序列限制,允许通过标签函数自定义处理。这些特性显著提升了异步编程和对象操作的便利性,其中对
系列文章目录
ES6中 对象字面量、解构赋值、var,let ,const、块及作用域、展开运算符与剩余参数相关知识点
ES6中 Map 集合类型知识点、常见使用场景、以及案例
ES6中 Set集合知识点、常见使用场景、以及案例
ES6中 迭代器与生成器,相关知识点、常见使用场景、以及案例
ES6中 Promise 相关知识点、常见使用场景、以及案例
ES6中 箭头函数、this的指向问题
ES7:includes()、指数运算符 详细教程
ES8:async/await、Object 的新静态方法、padStart/padEnd、函数参数列表末尾允许逗号 相关知识点
ES9:对象扩展与剩余参数运算符、异步迭代、Promise新增方法、模板字符串修订 相关知识点
ES10:数组扁平化、对象转换、字符串修剪、catch参数、Symbol描述文字、toString修、sort排序、标准化的globalThis 相关知识点
ES11:可选链操作符、空值合并运算符、allSettled、动态导入、matchAll、meta 相关知识点
ES12:逻辑赋值运算符、数字分隔符、replaceAll、Promise新方法、WeakRef、Setter/Getter 相关知识点
ES13:类私有属性和方法、顶层 await、at() 方法、Object.hasOwnProperty()、类静态块 相关知识点
ES14:数组的新“拷贝并修改”方法、findLast() 和 findLastIndex()、 Symbol 作为 WeakMap 的键 相关知识点
ES15:Object.groupBy() 和 Map.groupBy()、Promise.withResolvers() 相关知识点
ES16:Set 集合方法增强、Promise.try、迭代器助手、JSON 模块导入 相关知识
文章目录
ES9(也称为ECMAScript 2018)于2018 年6 月正式发布。虽然相对于ES6 来说它的改动不算“翻天覆地”,但它引入的几个核心特性(尤其是 对象展开 和 异步迭代)在现在的日常开发中几乎是必不可少的。
以下是ES9 引入的主要新特性及其详细介绍:
一、对象的Rest 参数与Spread 属性(Object Rest/Spread)
这是ES9 中最受欢迎的特性。此前ES6 仅支持数组的…操作,ES9 将其扩展到了对象上。
1.1 Spread 属性(扩展运算符)
用于浅拷贝对象或合并对象。
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
1.2 Rest 参数(剩余参数)
用于解构赋值,将剩下的属性收集到一个新对象中。
const { a, ...others } = { a: 1, b: 2, c: 3 };
console.log(others); // { b: 2, c: 3 }
二、异步迭代(Asynchronous Iteration)
在ES9 之前,JavaScript 的 for…of 循环是同步的。如果你尝试遍历一个包含多个Promise 的数组,循环会立即完成,而不会等待每个Promise 变为resolved。
ES9 引入了Symbol.asyncIterator和 for await…of 语法,专门用来解决“按顺序处理一系列异步操作”的问题。
2.1 为什么需要异步迭代?
想象一个场景:你需要从后端分页获取数据,每一页的请求都依赖前一页是否完成。
-
普通for…of:它只能处理同步的可迭代对象(如Array, Map, Set)。
-
异步迭代:它允许你像遍历普通数组一样,遍历一个“随时间推移产生数据”的序列。
示例A:遍历Promise 数组
即使数组里的元素是异步的,for await…of也会自动解包Promise,并等待前一个完成后再进入下一次循环。
const promises = [
Promise.resolve('🍎'),
new Promise(resolve => setTimeout(() => resolve('🍌'), 2000)), // 模拟延迟
Promise.resolve('🍇')
];
async function test() {
for await (const fruit of promises) {
console.log(fruit);
// 输出顺序:🍎 -> (等2秒) -> 🍌 -> 🍇
}
}
test();
2.2 进阶:异步生成器(Async Generators)
异步迭代最强大的地方在于结合异步生成器。你可以使用async function*定义一个函数,在内部使用yield配合await。
在前端开发中,「非同步迭代+ 异步产生器」最经典的场景就是处理 「流式数据」或「分段加载」 。
想像一个场景:你需要从后端获取大量数据,但为了不让页面卡顿,你希望每隔1 秒获取一批数据,并立即渲染到页面上,而不是等全部加载完才显示。
// 1. 精简的延时函数
const sleep = ms => new Promise(res => setTimeout(res, ms));
// 2. 异步生成器:模拟分批获取数据
async function* dataStream(total) {
for (let i = 1; i <= total; i++) {
await sleep(1000); // 模拟网络耗时
// 每次产生一组数据
yield [`数据项-${i}A`, `数据项-${i}B`];
}
}
// 3. 消费数据并渲染
async function startRender() {
const app = document.querySelector('#app');
console.log('开始接收流式数据...');
// 直接在循环中解构异步获取的 batch
for await (const batch of dataStream(5)) {
const html = batch.map(text => `<p>${text}</p>`).join('');
app.insertAdjacentHTML('beforeend', html);
console.log('渲染完成一批');
}
console.log('所有数据接收完毕');
}
startRender();
2.3 Promise.prototype.finally()
在此之前,我们只有.then()和.catch()。 ES9 增加了.finally(),无论Promise 最终是成功还是失败,里面的回调函数都会被执行。这通常用于关闭Loading 状态或清理资源。
fetch('/api/data')
.then(res => console.log(res))
.catch(err => console.error(err))
.finally(() => {
stopLoadingSpinner(); // 无论成功失败都会停止动画
});
ES6中 Promise 相关知识点、常见使用场景、以及案例
三、模板字符串修订(Template Literal Revision)
放宽了对模板字符串中转义序列的限制。在之前的版本中,如果模板字符串包含不合法的转义序列(如\u后面没跟4 个16 进制数字),会直接报错。 ES9 现在会将其设为undefined,允许开发者通过“标签模板”自定义处理这些错误的转义。
3.1 标签函数
标签函数(Tagged Templates)其实是ES6 引入的一种高级调用方式,但在ES9 中得到了重要的功能补丁(即放宽了转义限制)。
简单来说,它是模板字符串的“加工厂”。
3.1.1 什么是标签函数?
通常我们调用函数用fn(),但标签函数使用 fn模板字符串`` 的形式。
它会将模板字符串拆解为两部分传给函数:
-
字符串字面量数组:被${}分隔开的所有纯文本。
-
变量插值:所有的${}表达式的结果。
function myTag(strings, ...values) {
console.log("1. 字符串数组 (strings):", strings);
console.log("2. 变量值数组 (values):", values);
// 重新组合它们
return "加工后的结果";
}
const name = "张三";
const age = 25;
const job = "前端开发";
// 使用标签函数
myTag`这位博主叫${name},今年${age}岁,职业是${job}。`;
3.2 什么叫“非法转义”?
在JavaScript 的字符串中,反斜杠\是转义符。
-
\u后面必须跟着4 个十六进制数字(如\u0041代表"A")。
-
\x后面必须跟着2 个十六进制数字。
-
如果你写了\u123(少了一位)或者\u{bad},这在ES9 之前是语法错误(SyntaxError),整个程序会直接崩溃无法运行。
- ES9 的改进:从“崩溃”到“容错”
ES9放宽了这种限制。现在,如果遇到非法的转义序列:
JavaScript不再报错。
-
它会将该模板字符串的“熟值”(Cooked value)设为undefined。
-
但它保留了“原始值”(Raw value),让你可以通过标签函数(Tag Function)自己去解析。
处理Windows 文件路径
假设我们要处理一个包含\u的路径(例如用户文件夹名叫\users),这在以前是灾难。
// 标签函数:用来查看字符串的内部结构
function debugTag(strings) {
console.log('熟值 (Cooked):', strings[0]);
console.log('原始值 (Raw):', strings.raw[0]);
}
// 在 ES9 之前:
// 下面这行代码会直接导致程序报错:SyntaxError: Invalid Unicode escape sequence
// 因为 \u 后面跟着的是 sers,不是 4 位十六进制数
// debugTag`C:\users\admin`;
// 在 ES9 之后:
debugTag`C:\users\admin`;
/** * 输出结果:
* 熟值 (Cooked): undefined
* 原始值 (Raw): C:\users\admin
*/
更多推荐


所有评论(0)