for await…of
# for await...offor await...of 语句会在异步或者同步可迭代对象上创建一个迭代循环,包括 String,Array,Array-like 对象(比如arguments 或者NodeList),TypedArray,Map, Set和自定义的异步或者同步可迭代对象。其会调用自定义迭代钩子,并为每个不同属性的值执行语句。配合迭代异步生成器,例子如下:async function* asyncGenerator() {var i = 0while (i < 3) {yield i++}}(async function() {for await (num of asyncGenerator()) {console.log(num)}})()// 0// 1// 2
模板字符串(Template string)
# 模板字符串(Template string)ES9开始,模板字符串允许嵌套支持常见转义序列,移除对ECMAScript在带标签的模版字符串中转义序列的语法限制。不过,非法转义序列在"cooked"当中仍然会体现出来。它们将以undefined元素的形式存在于"cooked"之中,代码如下:function latex(str) {return { "cooked": str[0], "raw": str.raw[0] }}latex`\unicode` // { cooked: undefined, raw: "\\unicode" }
正则表达式反向(lookbehind)断言
# 正则表达式反向(lookbehind)断言首先我们得先知道什么是断言(Assertion)。断言(Assertion)是一个对当前匹配位置之前或之后的字符的测试, 它不会实际消耗任何字符,所以断言也被称为“非消耗性匹配”或“非获取匹配”。正则表达式的断言一共有 4 种形式:•(?=pattern) 零宽正向肯定断言(zero-width positive lookahead assertion)•(?!pattern) 零宽正向否定断言(zero-width negative lookahead assertion)•(?<=pattern) 零宽反向肯定断言(zero-width positive lookbehind assertion)•(?<!pattern) 零宽反向否定断言(zero-width negative lookbehind assertion)在ES9之前,JavaScript 正则表达式,只支持正向断言。正向断言的意思是:当前位置后面的字符串应该满足断言,但是并不捕获。例子如下:'fishHeadfishTail'.match(/fish(?=Head)/g) // ["fish"]反向断言和正向断言的行为一样,只是方向相反。例子如下:'abc123'.match(/(?<=(\d+)(\d+))$/) // ["", "1", "23", index: 6, input: "abc123", group
正则表达式 Unicode 转义
# 正则表达式中的Unicode转义符允许根据Unicode字符属性匹配Unicode字符。它允许区分字符类型,例如大写和小写字母,数学符号和标点符号。部分例子代码如下:// 匹配所有数字const regex = /^\p{Number}+$/u;regex.test('²³¹¼½¾') // trueregex.test('㉛㉜㉝') // trueregex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true// 匹配所有空格\p{White_Space}// 匹配各种文字的所有字母,等同于 Unicode 版的 \w[\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]// 匹配各种文字的所有非字母的字符,等同于 Unicode 版的 \W[^\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]// 匹配 Emoji/\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu// 匹配所有的箭头字符const regexArrows = /^\p{Block=Arrows}+$/u;regexArrows.test('←↑→↓↔↕↖↗↘↙⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇧⇩') // true具体的属性列表可查看:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes
正则表达式 s/dotAll 模式
# 正则表达式 s/dotAll 模式在以往的版本里,JS的正则的.只能匹配emoji跟行终结符以外的所有文本,例如:let regex = /./;regex.test('\n'); // falseregex.test('\r'); // falseregex.test('\u{2028}'); // falseregex.test('\u{2029}'); // falseregex.test('\v'); // trueregex.test('\f'); // trueregex.test('\u{0085}'); // true/foo.bar/.test('foo\nbar'); // false/foo[^]bar/.test('foo\nbar'); // true/foo.bar/.test('foo\nbar'); // false/foo[\s]bar/.test('foo\nbar'); // true但是在ES9之后,JS正则增加了一个新的标志 s 用来表示 dotAll,这可以匹配任意字符。代码如下:/foo.bar/s.test('foo\nbar'); // trueconst re = /foo.bar/s; // 等价于 const re = new RegExp('foo.bar', 's');re.test('foo\nbar'); // truere.dotAll; // truere.flags; // "s"
正则表达式命名捕获组
# 正则表达式命名捕获组在以往的版本里,JS的正则分组是无法命名的,所以容易混淆。例如下面获取年月日的例子,很容易让人搞不清哪个是月份,哪个是年份:const matched = /(\d{4})-(\d{2})-(\d{2})/.exec('2019-01-01')console.log(matched[0]); // 2019-01-01console.log(matched[1]); // 2019console.log(matched[2]); // 01console.log(matched[3]); // 01ES9引入了命名捕获组,允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。代码如下:const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;const matchObj = RE_DATE.exec('1999-12-31');const year = matchObj.groups.year; // 1999const month = matchObj.groups.month; // 12const day = matchObj.groups.day; // 31const RE_OPT_A = /^(?<as>a+)?$/;const matchObj = RE_OPT_A.exec('');matchObj.groups.as // undefined'as' in matchObj.groups // true
对象扩展操作符
# 对象扩展操作符ES6中添加了数组的扩展操作符,让我们在操作数组时更加简便,美中不足的是并不支持对象扩展操作符,但是在ES9开始,这一功能也得到了支持,例如:var obj1 = { foo: 'bar', x: 42 };var obj2 = { foo: 'baz', y: 13 };var clonedObj = { ...obj1 };// 克隆后的对象: { foo: "bar", x: 42 }var mergedObj = { ...obj1, ...obj2 };// 合并后的对象: { foo: "baz", x: 42, y: 13 }上面便是一个简便的浅拷贝。这里有一点小提示,就是Object.assign() 函数会触发 setters,而展开语法则不会。所以不能替换也不能模拟Object.assign() 。如果存在相同的属性名,只有最后一个会生效。
Promise.prototype.finally()
# Promise.prototype.finally()finally()方法会返回一个Promise,当promise的状态变更,不管是变成rejected或者fulfilled,最终都会执行finally()的回调。例子如下:fetch(url).then((res) => {console.log(res)}).catch((error) => {console.log(error)}).finally(() => {console.log('结束')})
