ES2018中4个有用的功能

开发 前端
ES2018 规范引入了四个新功能。这些功能包括异步迭代,rest/spread 属性,Promise.prototype.finally() 和正则表达式改进。本问将帮你了解这些 ES2018 功能的工作原理及使用方法。

ES2018 规范引入了四个新功能。这些功能包括异步迭代,rest/spread 属性,Promise.prototype.finally() 和正则表达式改进。本问将帮你了解这些 ES2018 功能的工作原理及使用方法。

异步迭代

异步迭代是讨论的比较少 ES2018 功能之一。虽然还有很多关于 ES2018 其他功能的讨论,但几乎没有关于异步迭代这方面的内容。通过异步迭代,我们可以得到异步的可迭代对象和迭代器。

这意味着你可以把 await 关键字与 for…of 循环放在一起使用。你可以用这些循环对可迭代对象进行迭代。可迭代对象的包括数组、map、set,NodeList,函数的 arguments 参数,TypedArray 等。

在 ES2018 之前,for...of 循环是同步的。如果你试着迭代涉及异步操作的可迭代对象并 await,则无法正常工作。循环本身会保持同步,基本上忽略 await ,并在其内部的异步操作可以完成之前完成迭代。

  1. // 下面的代码在 ES2018 之前不起作用,因为循环保持同步。 
  2. // 创建一个异步函数: 
  3. async function processResponses(someIterable) { 
  4.   // 对可迭代对象进行迭代 
  5.   for (let item of someIterable) { 
  6.     // 通过异步操作处理项目,例如promise: 
  7.     await processItem(item) 
  8.   } 

同时 for...of 循环也可以与异步代码一起使用。也就是说可以在遍历可迭代对象时执行一些异步操作。for...of 循环将会是异步的,让你能够等待异步操作完成。

需要记住的是在哪里使用 await 关键字。不需要把它放进循环体中,应该将其放在for...of关键字中 for 的后面。现在当你用 next() 方法获取异步迭代器的下个值时,将会得到一个 Promise。如果你想了解更多信息,可以在 GitHub 上去看看(https://github.com/tc39/proposal-async-iteration)。

  1. // 创建一个异步函数: 
  2. async function processResponses(someIterable) { 
  3.   //遍历可迭代对象并等待异步操作的结果 
  4.   for await (let item of someIterable) { 
  5.     processItem(item) 
  6.   } 

Rest/Spread 属性

rest 和 spread 并不是真正的新功能。两者都是在 ES6 中作为新的运算符引入的,它们很快就开始流行起来。可以说 JavaScript 程序员喜欢它们。唯一的问题是它们只能用在数组和参数上,不过 ES2018 把这两个功能引入了对象中。

rest 和 spread 运算符的语法都非常简单,由三个点(...)组成。这些点后面是要在其上使用 rest 或 spread 运算符的对象。接下来简单的讨论一下两者的工作原理。

对象的 rest 运算符

rest 运算符使你可以将对象的所有剩余对象属性属性提取到新对象上。要注意这些属性必须是可枚举的。如果你已经对某些属性使用了分解,那么 rest 运算符会只提取剩余的属性。

  1. // Rest example: 
  2.  
  3. const daysObj = { 
  4.   one: 'Monday', 
  5.   two: 'Tuesday', 
  6.   three: 'Wednesday', 
  7.   four: 'Thursday', 
  8.   five: 'Friday' 
  9.  
  10. //使用解构将变量的前两个属性分配给变量。 
  11. //然后,使用rest将其余属性分配给第三个变量。 
  12. const { one, two, ...restOfDays } = daysObj 
  13. // rest 仅提取 "three", "four" 和 "five"  
  14. // 因为我们已经提取了 "one" 和 "two"  
  15.  
  16. console.log(one) 
  17. // Output: 
  18. // 'Monday' 
  19.  
  20. console.log(two) 
  21. // Output: 
  22. // 'Tuesday' 
  23.  
  24. console.log(restOfDays) 
  25. // Output: 
  26. // { three: 'Wednesday', four: 'Thursday', five: 'Friday' } 

如果要对对象使用 rest 运算符,需要记住两点:首先,只能用一次,除非把它用在嵌套对象上。其次,必须在最后使用。这就是为什么在上面的例子中,在解构前两个属性之后而不是之前看到它的原因。

  1. // 这行代码不起作用,因为把 rest 运算符用在了最前面: 
  2. const { ...all, one, two } = { one: 1, two: 2, three: 3 } 
  3.  
  4. //这行能起作用: 
  5. const { one, two, ...all } = { one: 1, two: 2, three: 3 } 
  6.  
  7. // 这行不起作用,因为同一级别上有多个 rest 运算符: 
  8. const { one, ...some, ...end } = { /* some properties */ } 
  9.  
  10. // 这行能起作用,在多个级别上的多个 rest 运算符: 
  11. const { one, {...secondLevel }, ...firstLevel } = { /* some properties */ } 

对象的 spread 运算符

spread 运算符的作用是可以通过插入另一个对象的所有属性来创建新对象。Spread 运算符还允许你从多个对象插入属性。也可以把这个运算符与添加新属性结合使用。

  1. // Spread example: 
  2. const myOriginalObj = { name: 'Joe Doe', age: 33 } 
  3. // 用 spread 运算符创建新对象: 
  4. const myNewObj = { ...myOriginalObj } 
  5.  
  6. console.log(myNewObj) 
  7. // Output: 
  8. // { name: 'Joe Doe', age: 33 } 
  9.  
  10.  
  11. // 添加属性的例子: 
  12. const myOriginalObj = { name: 'Caesar' } 
  13. // 用 spread 运算符创建新对象 
  14. // 并添加新的属性“genre”: 
  15. const myNewObj = { ...myOriginalObj, genre: 'Strategy' } 
  16.  
  17. console.log(myNewObj) 
  18. // Output: 
  19. // { 
  20. //   name: 'Caesar', 
  21. //   genre: 'Strategy' 
  22. // } 
  23.  
  24.  
  25. // Spread 运算符并合并两个对象: 
  26. const myObjOne = { title: 'Eloquent JavaScript' } 
  27. const myObjTwo = { author: 'Marijn Haverbeke' } 
  28.  
  29. const myNewObj = { ...myObjOne, ...myObjTwo } 
  30.  
  31. console.log(myNewObj) 
  32. // Output: 
  33. // { 
  34. //   title: 'Eloquent JavaScript', 
  35. //   author: 'Marijn Haverbeke' 
  36. // } 

当从多个对象插入属性并添加新属性时,顺序很重要。

我来解释一下,假设你要用 spread 运算符基于两个现有对象创建一个新对象。第一个已有对象中包含具有某些值的属性 title。第二个对象也包含属性 title,但是值不一样。最终到底取哪个 title?

答案是最后一个。如果对第一个对象使用 spread 运算符,然后再对第二个对象使用,则第二个 title 会生效。如果你将 spread 运算符永在第二个对象上,则第一个 title会生效。

  1. // Spread 运算符并合并两个对象: 
  2. const myObjOne = { 
  3.   title: 'Eloquent JavaScript', 
  4.   author: 'Marijn Haverbeke', 
  5.  
  6. const myObjTwo = { 
  7.   title: 'You Don\'t Know JS Yet', 
  8.   language: 'English' 
  9.  
  10. // 用 spread 运算符通过组合 “myObjOne” 和 “myObjTwo” 创建新对象 
  11. // 注意:“myObjTwo” 中的 “title” 会将覆盖 “myObjTwo” 的 “title” 
  12. // 因为“ myObjTwo”排在最后。 
  13. const myNewObj = { ...myObjOne, ...myObjTwo } 
  14.  
  15. console.log(myNewObj) 
  16. // Output: 
  17. // { 
  18. //   title: "You Don't Know JS Yet", 
  19. //   author: 'Marijn Haverbeke', 
  20. //   language: 'English' 
  21. // } 
  22.  
  23.  
  24. // 注意:“myObjOne” 中的 “title” 将覆盖 “myObjTwo” 的 “title” 
  25. const myNewObj = { ...myObjTwo, ...myObjOne } 
  26.  
  27. console.log(myNewObj) 
  28. // Output: 
  29. // { 
  30. //   title: 'Eloquent JavaScript', 
  31. //   language: 'English', 
  32. //   author: 'Marijn Haverbeke' 
  33. // } 

Promise.prototype.finally()

一开始有两个用于 Promise 的回调函数。其中一个是 then(),在实现诺 Promise 执行。第二个是catch(),在 promise 被拒绝或 then() 抛出异常时执行。ES2018 增加了用于 Promise 的第三个回调函数 finally()。

每次完成 promise 时,都会执行 finally() 回调,不管 promise 是否完成。这个回调的一般用于执行应始终发生的操作。例如关闭模态对话框、关闭数据库连接或进行某些清理。

  1. // finally() example: 
  2. fetch() 
  3.   .then(response => response.json()) 
  4.   .then(data => console.log(data)) 
  5.   .catch(error => console.log(error)) 
  6.   //最后做点什么: 
  7.   .finally(() => console.log('Operation done.')) 

对正则表达式的改进

ES2018 还对正则表达式功能进行了的一些改进。这些改进包括 s(dotAll) 标志,后行断言,命名捕获组和 unicode 属性转义。

s(dotAll)

首先是 s(dotAll) 。与点(.)不同,s(dotAll) 允许对换行符及表情符号进行匹配。

  1. // s(dotAll) example: 
  2. /hello.world/.test('hello\nworld') 
  3. // Output: 
  4. // false 
  5.  
  6. /hello.world/s.test('hello\nworld') 
  7. // Output: 
  8. // true 

后行断言

在ES2018之前,JavaScript仅支持先行断言。先行断言用于基于其后的文本来匹配模式。在 ES2018 中增加了对后行断言的支持。通过它可以基于模式之前的文本模式来进行匹配。后行断言的语法为 ?<=。

  1. // 后行断言例子: 
  2. /(?<=green) apple/.test('One red apple is on the table.') 
  3. // Output: 
  4. // false 
  5.  
  6. /(?<=green) apple/.test('One green apple is on the table.') 
  7. // Output: 
  8. // true 

断言后面也有一个反向的回溯。仅当子字符串之前没有断言时,此断言才与模式匹配。对后行断言取反操作的语法是 ?<!。

  1. /(?<!green) apple/.test('One red apple is on the table.') 
  2. // Output: 
  3. // true 
  4.  
  5. /(?<!green) apple/.test('One green apple is on the table.') 
  6. // Output: 
  7. // false 

命名捕获组

另一个被 ES2018 引入到正则表达式的好功能是命名捕获组。命名捕获组的语法为 ?<some_name>。

  1. const date_pattern = /(?<day>\d{2})\/(?<month>\d{2})\/(?<year>\d{4})/ 
  2. const result = date_pattern.exec('11/12/2021') 
  3.  
  4. console.log(result) 
  5. // Output: 
  6. // [ 
  7. //   '11/12/2021', 
  8. //   '11', 
  9. //   '12', 
  10. //   '2021', 
  11. //   index: 0, 
  12. //   input: '11/12/2021', 
  13. //   groups: [Object: null prototype] { day: '11', month: '12', year: '2021' } 
  14. // ] 
  15.  
  16. console.log(result.groups.day) 
  17. // Output: 
  18. // '11' 
  19.  
  20. console.log(result.groups.month) 
  21. // Output: 
  22. // '12' 
  23.  
  24. console.log(result.groups.year) 
  25. // Output: 
  26. // '2021' 

Unicode 属性转义

每个 unicode 字符都有许多属性。例如:空白字符,大小写,字母,ASCII,表情符号等。现在你可以在正则表达式中访问这些属性了。

要使用这个功能需要做两件事。首先必须使用 /u 标志。这个标志告诉 JavaScript 你的字符串是一系列 Unicode 代码点。第二是使用 \p{}。你要检查的属性位于大括号之间,反之则用 \P{}。

  1. // 用俄语创建一个字符串(西里尔字母): 
  2. const myStrCyr = 'Доброе утро' 
  3.  
  4. //创建英文字符串(拉丁字母): 
  5. const myStrLat = 'Good morning' 
  6.  
  7. //测试“ myStrCyr”是否包含西里尔字符: 
  8. /\p{Script=Cyrillic}/u.test(myStrCyr) // true 
  9.  
  10. //测试“ myStrLat”是否包含西里尔字符: 
  11. /\p{Script=Cyrillic}/u.test(myStrLat) // false 
  12.  
  13. // 测试“myStrLat” 是否包含西里尔字符: 
  14. /\p{Script=Latin}/u.test(myStrCyr) // false 
  15.  
  16. // 测试“myStrLat” 是否包含拉丁语字符: 
  17. /\p{Script=Latin}/u.test(myStrLat) // true 

 

责任编辑:赵宁宁 来源: 前端先锋
相关推荐

2021-03-09 09:14:27

ES2019JavaScript开发

2013-11-05 10:03:22

Eclipse功能

2013-07-12 09:45:16

PHP功能

2020-06-21 13:57:21

JavaScript开发代码

2021-04-29 08:28:24

架构参数传递

2020-10-14 11:10:52

ES2020JavaScript前端

2020-10-23 19:50:15

ES2020Javascript1前端

2020-05-20 13:45:52

Linuxtouch命令

2010-07-14 10:02:47

IMAP4功能

2020-06-22 08:09:22

GitHub工具开发

2014-09-18 09:50:32

Ruby on Rai

2015-07-22 17:19:20

Linux命令技巧

2022-05-05 19:00:22

PythonPython特性

2023-11-24 08:31:03

ECMAScriptES2021

2023-09-07 16:23:22

2015-10-27 11:02:06

Web开发CSS 库

2015-10-27 15:45:27

Web开发CSS代码

2022-01-11 19:31:33

GNOME桌面应用

2014-06-13 11:26:53

CSS库Web开发

2023-10-26 07:47:35

JavaScript代码变量
点赞
收藏

51CTO技术栈公众号