复习ES(6-11)语法之ES9
目录
异步迭代
- for-await-of
- Symbol.asyncIterator
for...of
循环用于遍历同步的 Iterator 接口。
function getPromise(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
value: time,
done: false,
});
}, time);
});
}
const arr = [getPromise(1000), getPromise(2000), getPromise(3000)];
for (let item of arr) {
console.log(item); // 状态都是pending Promise { <pending> }
}
新引入的for await...of
循环,则是用于遍历异步的 Iterator 接口。Symbol.asyncIterator
依然遵守迭代器协议
arr[Symbol.asyncIterator] = function () {
let nextIndex = 0;
return {
next() {
return nextIndex < arr.length
? arr[nextIndex++]
: Promise.resolve({
value: undefined,
done: true,
});
},
};
};
async function test() {
for await (let item of arr) {
console.log(item); // 状态都是pending Promise { <pending> }
}
}
test();
正则表达式扩展
- dotAll
正则表达式中,点(.
)是一个特殊字符,代表任意的单个字符,但是有两个例外。一个是四个字节的 UTF-16 字符,这个可以用u
修饰符解决;另一个是行终止符
所谓行终止符,就是该字符表示一行的终结。以下四个字符属于“行终止符”。
- U+000A 换行符(
\n
) - U+000D 回车符(
\r
) - U+2028 行分隔符(line separator)
- U+2029 段分隔符(paragraph separator)
const reg = /./;
console.log(reg.test("5")); // true
console.log(reg.test("x")); // true
console.log(reg.test("\n")); // false
console.log(reg.test("\r")); // false
console.log(reg.test("\u{2028}")); // false
ES2018 引入s
修饰符,使得.
可以匹配任意单个字符。这被称为dotAll
模式,即点(dot)代表一切字符。
const reg = /./s;
console.log(reg.test("5")); // true
console.log(reg.test("x")); // true
console.log(reg.test("\n")); // true
console.log(reg.test("\r")); // true
console.log(reg.test("\u{2028}")); // true
所以,正则表达式还引入了一个dotAll
属性,返回一个布尔值,表示该正则表达式是否处在dotAll
模式。
const reg = /./;
console.log(reg.dotAll); // false
const reg = /./s;
console.log(reg.dotAll); // true
- 具名组分配
正则表达式使用圆括号进行组匹配。正则表达式里面有三组圆括号。使用exec
方法,就可以将这三组匹配结果提取出来。
const date = /(\d{4})-(\d{2})-(\d{2})/.exec("2023-07-10");
console.log(date);
console.log(date[1]);
console.log(date[2]);
console.log(date[3]);
ES2018 引入了具名组匹配
,允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。
“具名组匹配”在圆括号内部,模式的头部添加“问号 + 尖括号 + 组名”,然后就可以在exec
方法返回结果的groups
属性上引用该组名。
const date = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/.exec("2023-07-10");
console.log(date.groups.year);
console.log(date.groups.month);
console.log(date.groups.day);
- 后行断言
“先行断言”指的是,x
只有在y
前面才匹配,必须写成/x(?=y)/
。
“先行否定断言”指的是,x
只有不在y
前面才匹配,必须写成/x(?!y)/
。
const str = "zzzapple";
console.log(str.match(/zzz(?=apple)/));
console.log(str.match(/zzz(?=banana)/)); // null
console.log(str.match(/zzz(?!banana)/));
“后行断言”正好与“先行断言”相反,x
只有在y
后面才匹配,必须写成/(?<=y)x/
。
“后行否定断言”则与“先行否定断言”相反,x
只有不在y
后面才匹配,必须写成/(?<!y)x/
。
console.log(str.match(/(?<=zzz)apple/));
console.log(str.match(/(?<=zzz)banana/)); // null
console.log(str.match(/(?<!zzz)apple/)); // null
对象扩展
对象的扩展运算符(...
)用于取出参数对象的所有可遍历属性,不是引用而是真正拷贝到当前对象之中。
const obj1 = {
name: "zzz",
};
const obj2 = {
age: 18,
};
const obj = {
...obj1,
...obj2,
};
console.log(obj); // { name: 'zzz', age: 18 }
obj.age = 22;
console.log(obj2.age); // 18
如果合并2个对象有相同属性,后者属性会取代前者。
const obj1 = {
name: "zzz",
age: 34,
};
const obj2 = {
age: 18,
};
const obj = {
...obj1,
...obj2,
};
console.log(obj); // { name: 'zzz', age: 18 }
可以通过rest
参数提取对象中的属性
const obj = {
name: "zzz",
age: 18,
lang: "zh-CN",
};
const { name, ...rest } = obj;
console.log(name); // zzz
console.log(rest); // { age: 18, lang: 'zh-CN' }
Promise.prototype.finally()
finally()
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("success");
// reject('fail')
}, 1000);
})
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})
.finally(() => {
console.log("finally");
});
放松模板字符串文字限制
const foo = (arg) => {
console.log(arg);
};
foo`\u{61} and \unicode`;
ES2018 放松了对标签模板里面的字符串转义的限制。如果遇到不合法的字符串转义,就返回undefined
,而不是报错,并且从raw
属性上面可以得到原始字符串。