for await…of

  1. # for await...of
  2. for await...of 语句会在异步或者同步可迭代对象上创建一个迭代循环,包括 StringArrayArray-like 对象(比如arguments 或者NodeList),TypedArrayMap Set和自定义的异步或者同步可迭代对象。其会调用自定义迭代钩子,并为每个不同属性的值执行语句。
  3. 配合迭代异步生成器,例子如下:
  4. async function* asyncGenerator() {
  5. var i = 0
  6. while (i < 3) {
  7. yield i++
  8. }
  9. }
  10. (async function() {
  11. for await (num of asyncGenerator()) {
  12. console.log(num)
  13. }
  14. })()
  15. // 0
  16. // 1
  17. // 2

模板字符串(Template string)

  1. # 模板字符串(Template string
  2. ES9开始,模板字符串允许嵌套支持常见转义序列,移除对ECMAScript在带标签的模版字符串中转义序列的语法限制。
  3. 不过,非法转义序列在"cooked"当中仍然会体现出来。它们将以undefined元素的形式存在于"cooked"之中,代码如下:
  4. function latex(str) {
  5. return { "cooked": str[0], "raw": str.raw[0] }
  6. }
  7. latex`\unicode` // { cooked: undefined, raw: "\\unicode" }

正则表达式反向(lookbehind)断言

  1. # 正则表达式反向(lookbehind)断言
  2. 首先我们得先知道什么是断言(Assertion)。
  3. 断言(Assertion)是一个对当前匹配位置之前或之后的字符的测试, 它不会实际消耗任何字符,所以断言也被称为“非消耗性匹配”或“非获取匹配”。
  4. 正则表达式的断言一共有 4 种形式:
  5. •(?=pattern) 零宽正向肯定断言(zero-width positive lookahead assertion)•(?!pattern) 零宽正向否定断言(zero-width negative lookahead assertion)•(?<=pattern) 零宽反向肯定断言(zero-width positive lookbehind assertion)•(?<!pattern) 零宽反向否定断言(zero-width negative lookbehind assertion)
  6. ES9之前,JavaScript 正则表达式,只支持正向断言。正向断言的意思是:当前位置后面的字符串应该满足断言,但是并不捕获。例子如下:
  7. 'fishHeadfishTail'.match(/fish(?=Head)/g) // ["fish"]
  8. 反向断言和正向断言的行为一样,只是方向相反。例子如下:
  9. 'abc123'.match(/(?<=(\d+)(\d+))$/) // ["", "1", "23", index: 6, input: "abc123", group

正则表达式 Unicode 转义

  1. # 正则表达式中的Unicode转义符允许根据Unicode字符属性匹配Unicode字符。它允许区分字符类型,例如大写和小写字母,数学符号和标点符号。
  2. 部分例子代码如下:
  3. // 匹配所有数字
  4. const regex = /^\p{Number}+$/u;
  5. regex.test('²³¹¼½¾') // true
  6. regex.test('㉛㉜㉝') // true
  7. regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true
  8. // 匹配所有空格
  9. \p{White_Space}
  10. // 匹配各种文字的所有字母,等同于 Unicode 版的 \w
  11. [\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]
  12. // 匹配各种文字的所有非字母的字符,等同于 Unicode 版的 \W
  13. [^\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]
  14. // 匹配 Emoji
  15. /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu
  16. // 匹配所有的箭头字符
  17. const regexArrows = /^\p{Block=Arrows}+$/u;
  18. regexArrows.test('←↑→↓↔↕↖↗↘↙⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇧⇩') // true
  19. 具体的属性列表可查看:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes

正则表达式 s/dotAll 模式

  1. # 正则表达式 s/dotAll 模式
  2. 在以往的版本里,JS的正则的.只能匹配emoji跟行终结符以外的所有文本,例如:
  3. let regex = /./;
  4. regex.test('\n'); // false
  5. regex.test('\r'); // false
  6. regex.test('\u{2028}'); // false
  7. regex.test('\u{2029}'); // false
  8. regex.test('\v'); // true
  9. regex.test('\f'); // true
  10. regex.test('\u{0085}'); // true
  11. /foo.bar/.test('foo\nbar'); // false
  12. /foo[^]bar/.test('foo\nbar'); // true
  13. /foo.bar/.test('foo\nbar'); // false
  14. /foo[\s]bar/.test('foo\nbar'); // true
  15. 但是在ES9之后,JS正则增加了一个新的标志 s 用来表示 dotAll,这可以匹配任意字符。代码如下:
  16. /foo.bar/s.test('foo\nbar'); // true
  17. const re = /foo.bar/s; // 等价于 const re = new RegExp('foo.bar', 's');
  18. re.test('foo\nbar'); // true
  19. re.dotAll; // true
  20. re.flags; // "s"

正则表达式命名捕获组

  1. # 正则表达式命名捕获组
  2. 在以往的版本里,JS的正则分组是无法命名的,所以容易混淆。例如下面获取年月日的例子,很容易让人搞不清哪个是月份,哪个是年份:
  3. const matched = /(\d{4})-(\d{2})-(\d{2})/.exec('2019-01-01')
  4. console.log(matched[0]); // 2019-01-01
  5. console.log(matched[1]); // 2019
  6. console.log(matched[2]); // 01
  7. console.log(matched[3]); // 01
  8. ES9引入了命名捕获组,允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。代码如下:
  9. const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
  10. const matchObj = RE_DATE.exec('1999-12-31');
  11. const year = matchObj.groups.year; // 1999
  12. const month = matchObj.groups.month; // 12
  13. const day = matchObj.groups.day; // 31
  14. const RE_OPT_A = /^(?<as>a+)?$/;
  15. const matchObj = RE_OPT_A.exec('');
  16. matchObj.groups.as // undefined
  17. 'as' in matchObj.groups // true

对象扩展操作符

  1. # 对象扩展操作符
  2. ES6中添加了数组的扩展操作符,让我们在操作数组时更加简便,美中不足的是并不支持对象扩展操作符,但是在ES9开始,这一功能也得到了支持,例如:
  3. var obj1 = { foo: 'bar', x: 42 };
  4. var obj2 = { foo: 'baz', y: 13 };
  5. var clonedObj = { ...obj1 };
  6. // 克隆后的对象: { foo: "bar", x: 42 }
  7. var mergedObj = { ...obj1, ...obj2 };
  8. // 合并后的对象: { foo: "baz", x: 42, y: 13 }
  9. 上面便是一个简便的浅拷贝。这里有一点小提示,就是Object.assign() 函数会触发 setters,而展开语法则不会。所以不能替换也不能模拟Object.assign()
  10. 如果存在相同的属性名,只有最后一个会生效。

Promise.prototype.finally()

  1. # Promise.prototype.finally()
  2. finally()方法会返回一个Promise,当promise的状态变更,不管是变成rejected或者fulfilled,最终都会执行finally()的回调。
  3. 例子如下:
  4. fetch(url)
  5. .then((res) => {
  6. console.log(res)
  7. })
  8. .catch((error) => {
  9. console.log(error)
  10. })
  11. .finally(() => {
  12. console.log('结束')
  13. })