博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
这篇是ECMAScript 2016、2017和2018中所有新特性的示例!
阅读量:6263 次
发布时间:2019-06-22

本文共 11464 字,大约阅读时间需要 38 分钟。

图片描述

跟踪JavaScript (ECMAScript)中的新内容是很困难的,而且更难找到有用的代码示例。

因此,在本文中将介绍 在ES2016、ES2017和ES2018中添加的已完成提案中列出的所有18个特性,并给出有用的示例。

图片描述

1.Array.prototype.includes

include 是数组上的一个简单实例方法,可以轻松查找数组中是否有指定内容(包括 NaN)。

图片描述

2.求幂操作符

像加法和减法这样的数学运算分别有像 + 和 - 这样运算符。与它们类似,** 运算符通常用于指数运算。在ECMAScript 2016中,引入了 ** 代替 Math.pow。

图片描述

图片描述

1.Object.values()

Object.values()是一个类似于Object.keys()的新函数,但返回对象自身属性的所有值,不包括原型链中的任何值。

图片描述

2.Object.entries()

Object.entries()与Object.keys 类似,但它不是仅返回键,而是以数组方式返回键和值。 这使得在循环中使用对象或将对象转换为映射等操作变得非常简单。

例一:

图片描述

例二:

图片描述

3.字符串填充

在String.prototype中添加了两个实例方法:String.prototype.padStart 和 String.prototype.padEnd, 允许在初始字符串的开头或末尾追加/前置空字符串或其他字符串。

'someString'.padStart(numberOfCharcters [,stringForPadding]); '5'.padStart(10) // '          5''5'.padStart(10, '=*') //'=*=*=*=*=5''5'.padEnd(10) // '5         ''5'.padEnd(10, '=*') //'5=*=*=*=*='
当我们想要在漂亮的打印显示或终端打印进行对齐时,这非常有用。

3.1 padStart 例子:

在下面的例子中,有一个不同长度的数字列表。我们希望在“0”为追加符让所有项长度都为10位,以便显示,我们可以使用padStart(10, '0')轻松实现这一点。

图片描述

3.2 padEnd 例子:

当我们打印多个不同长度的项目并想要右对齐它们时,padEnd非常有用。

下面的示例是关于padEnd、padStart和 Object.entries 的一个很好的实际示例:

图片描述

const cars = {  '?BMW': '10',  '?Tesla': '5',  '?Lamborghini': '0'}Object.entries(cars).map(([name, count]) => {  console.log(`${name.padEnd(20, ' -')}  Count: ${count.padStart(3, '0')}`)})// 打印// ?BMW - - - - - - -  Count: 010// ?Tesla - - - - - -  Count: 005// ?Lamborghini - - -  Count: 000

3.3 ⚠️ 注意padStart和padEnd 在Emojis和其他双字节字符上的使用

Emojis和其他双字节字符使用多个unicode字节表示。所以padStart padEnd可能不会像预期的那样工作!⚠️

例如:假设我们要垫达到10个字符的字符串的心❤️emoji。结果如下:

'heart'.padStart(10, "❤️"); // prints.. '❤️❤️❤heart'

这是因为 ❤️ 长2个字节(' u2764 uFE0F')! 单词 heart 是5个字符,所以我们只剩下5个字符来填充。 所以 JS 使用 ('u2764uFE0F' ) 填充两颗心并生成 ❤️❤️。 对于最后一个,它只使用 ('u2764uFE0F' ) 的第一个字节(u2764)来生成,所以是 ❤;

4.Object.getOwnPropertyDescriptors

此方法返回给定对象的所有属性的所有属性(包括getter setter set方法),添加这个的主要目的是允许浅 拷贝/克隆到另一个对象中的对象,类似 bject.assign。

Object.assign 浅拷贝除原始对象的 getter 和 setter 方法之外的所有属性。

下面的示例显示了 Object.assign 和 Object.getOwnPropertyDescriptors 以及Object.defineProperties 之间的区别,以将原始对象 Car 复制到新对象 ElectricCar 中。 可以看到使用 Object.getOwnPropertyDescriptors,discount 的 getter 和 setter 函数也被复制到目标对象中。

图片描述

使用 Object.defineProperties

图片描述

var Car = {  name: 'BMW',  price: 1000000,  set discount(x) {   this.d = x;  },  get discount() {   return this.d;  }, }; console.log(Object.getOwnPropertyDescriptor(Car, 'discount')); // 打印 // {  //   get: [Function: get], //   set: [Function: set], //   enumerable: true, //   configurable: true // } // 使用 Object.assign 拷贝对象 const ElectricCar = Object.assign({}, Car); //Print details of ElectricCar object's 'discount' property console.log(Object.getOwnPropertyDescriptor(ElectricCar, 'discount')); // 打印 // {  //   value: undefined, //   writable: true, //   enumerable: true, //   configurable: true     // } //  //⚠️请注意,“discount” 属性的 ElectricCar 对象中缺少getter和setter!??  //Copy Car's properties to ElectricCar2 using Object.defineProperties  //and extract Car's properties using Object.getOwnPropertyDescriptors const ElectricCar2 = Object.defineProperties({}, Object.getOwnPropertyDescriptors(Car)); //Print details of ElectricCar2 object's 'discount' property console.log(Object.getOwnPropertyDescriptor(ElectricCar2, 'discount')); //prints.. // { get: [Function: get],  ?????? //   set: [Function: set],  ?????? //   enumerable: true, //   configurable: true  // } // 请注意,在ElectricCar2对象中存在“discount”属性的getter和setter !

5.函数参数的尾逗号

ES2017允许函数的最后一个参数有尾逗号(trailing comma), 此前,函数定义和调用时,都不允许最后一个参数后面出现逗号。这一变化将鼓励开发人员停止丑陋的“行以逗号开头”的习惯。这对于版本管理系统来说,就会显示添加逗号的那一行也发生了变动。

图片描述

6.Async/Await

到目前为止,个人感受是这是最重要和最有用的功能。 async 函数允许我们不处理回调地狱,并使整个代码看起来很简单。

async 关键字告诉 JavaScript 编译器以不同的方式对待函数。每当编译器到达函数中的 await 关键字时,它就会暂停。它假定 wait 之后的表达式返回一个 promise ,并在进一步移动之前等待该 promise 被 resolved 或 rejected。

在下面的示例中,getAmount 函数调用两个异步函数getUser和getBankBalance。使用 async await更加优雅和简单达到有有序的调用 getUser 与 getBankBalance。

图片描述

6.1.async 函数默认返回一个 promise

如果您正在等待 async 函数的结果,则需要使用 Promise 的 then 语法来捕获其结果。

在以下示例中,我们希望使用 console.log 来打印结果但是不在 doubleAndAdd 函数里面操作。 因为 async 返回是一个 promise 对象,所以可以在 then 里面执行我们一些打印操作。

图片描述

6.2 并行调用 async/await

在前面的例子中,我们调用doubleAfterlSec ,但每次我们等待一秒钟(总共2秒)。 相反,我们可以使用 Promise.all 将它并行化为一个并且互不依赖于。

图片描述

6.3 async/await 函数对错误的处理

在使用async/wait时,有多种方法可以处理错误。

方法一:在函数内使用 try catch

图片描述

async function doubleAndAdd(a, b) {  try {   a = await doubleAfter1Sec(a);   b = await doubleAfter1Sec(b);  } catch (e) {   return NaN; //return something  } return a + b; } doubleAndAdd('one', 2).then(console.log); // NaN doubleAndAdd(1, 2).then(console.log); // 6 function doubleAfter1Sec(param) {  return new Promise((resolve, reject) => {   setTimeout(function() {    let val = param * 2;    isNaN(val) ? reject(NaN) : resolve(val);   }, 1000);  }); }

方法二:在 await 后使用 catch 捕获错误

图片描述

// 方法二:在 await 后使用 catch 获取错误async function doubleAndAdd(a, b) {  a = await doubleAfter1Sec(a).catch(e => console.log('"a" is NaN')); // ?  b = await doubleAfter1Sec(b).catch(e => console.log('"b" is NaN')); // ?  if (!a || !b) {   return NaN;  }  return a + b; }  doubleAndAdd('one', 2).then(console.log); // NaN  and logs:  "a" is NaN doubleAndAdd(1, 2).then(console.log); // 6 function doubleAfter1Sec(param) {  return new Promise((resolve, reject) => {   setTimeout(function() {    let val = param * 2;    isNaN(val) ? reject(NaN) : resolve(val);   }, 1000);  }); }

方法三:在整个的 async-await 函数捕获错误

图片描述

//方法三:在整个的 async-await 函数捕获错误async function doubleAndAdd(a, b) {  a = await doubleAfter1Sec(a);  b = await doubleAfter1Sec(b);  return a + b; }  doubleAndAdd('one', 2) .then(console.log) .catch(console.log); // ???<------- use "catch" function doubleAfter1Sec(param) {  return new Promise((resolve, reject) => {   setTimeout(function() {    let val = param * 2;    isNaN(val) ? reject(NaN) : resolve(val);   }, 1000);  }); }

图片描述

这是一个巨大的、相当高级的特性,是JS引擎的核心增强。

其主要原理是在 JavaScript 中引入某种多线程特性,以便JS开发人员将来可以通过允许自己管理内存而不是让 JS 引擎管理内存来编写高性能的并发程序。

这是通过一种名为 的新类型的全局对象实现的,该对象本质上是将数据存储在共享内存空间中。因此,这些数据可以在主JS线程和web工作线程之间共享。

到目前为止,如果我们想在主 JS 线程和 web 工作者之间共享数据,我们必须复制数据并使用postMessage 将其发送到另一个线程。

你只需使用SharedArrayBuffer,数据就可以立即被主线程和多个web工作线程访问。workers 之间的协调变得更简单和更快(与 postMessage() 相比)。

但是在线程之间共享内存会导致竞争条件。为了帮助避免竞争条件,引入了 “Atomics” 全局对象。 Atomics 提供了各种方法来在线程使用其数据时锁定共享内存。 它还提供了安全地更新该共享内存中的搜索数据的方法。

如果你这对个感兴趣,可以阅读以下文章:

2. Tagged Template literal restriction removed

首先,我们需要知道的什么是 ls(“标记的模板文字”),以便更好地理解这个特性。Template literals是一个ES2015特性,它使用反引号包含一个字符串字面量,并且支持嵌入表达式和换行,如:

图片描述

下面的例子显示,我们的自定义“Tag” 函数 greet 添加了一天中的时间,比如“Good Morning!” “Good afternoon” 等等,取决于一天中的时间字符串的文字和返回自定义字符串。

图片描述

function greet(hardCodedPartsArray, ...replacementPartsArray) {  console.log(hardCodedPartsArray); //[ 'Hello ', '!' ]  console.log(replacementPartsArray); //[ 'Raja' ]  let str = '';  hardCodedPartsArray.forEach((string, i) => {   if (i < replacementPartsArray.length) {    str += `${string} ${replacementPartsArray[i] || ''}`;   } else {    str += `${string} ${timeGreet()}`; //<-- 追加 Good morning/afternoon/evening here   }  });  return str; } const firstName = 'Raja'; const greetings = greet`Hello ${firstName}!`; //??<-- Tagged literal console.log(greetings); //'Hello  Raja! Good Morning!' ? function timeGreet() {  const hr = new Date().getHours();  return hr < 12   ? 'Good Morning!'   : hr < 18 ? 'Good Afternoon!' : 'Good Evening!'; }

现在我们讨论了什么是“标记”函数,许多人希望在不同的领域中使用这个特性,比如在Terminal中用于命令,在组成 uri 的 HTTP 请求中,等等。

⚠️ 带标记字符串文字的问题

问题是ES2015和ES2016规范不允许使用像“u”(unicode)、“x”(十六进制)这样的转义字符,除非它们看起来完全像“ u00A9”或u{2F804}或xA9。

因此,如果你有一个内部使用其他域规则(如终端规则)的标记函数,可能需要使用看起来不像 u0049或 u {@ F804}的 ubla123abla,那么你会得到一个语法错误,

function myTagFunc(str) {  return { "cooked": "undefined", "raw": str.raw[0] }} var str = myTagFunc `hi \ubla123abla`; //call myTagFuncstr // { cooked: "undefined", raw: "hi \\unicode" }

3.用于正则表达式的“dotall”标志

目前在正则表达式中,虽然点(“.”)应该匹配单个字符,但它不匹配像 n r f 等新行字符。

例如:

//Before/first.second/.test('first\nsecond'); //false

这种增强使 点 运算符能够匹配任何单个字符。为了确保它不会破坏任何东西,我们需要在创建正则表达式时使用s标志。

//ECMAScript 2018/first.second/s.test('first\nsecond'); //true   Notice: /s ??

更多的方法,请看:

图片描述

4.RegExp Named Group Captures

这种增强 RegExp特性借鉴于像Python、Java等其他语言,因此称为“命名组”。这个特性允许编写开发人员以(<name>…)格式为 RegExp 中的组的不同部分提供名称(标识符),使用可以用这个名称轻松地获取他们需要的任何组。

4.1 Named group 的基础用法

在下面的示例中,我们使用 (?<year>) (?<month>) 和 (?<day>) 名称对日期正则表达式的不同部分进行分组。结果对象现在将包含一个groups属性,该属性具有 year、month和 day 的相应值。

图片描述

let re1 = /(\d{4})-(\d{2})-(\d{2})/;let result1 = re1.exec('2015-01-02');console.log(result1);// [ '2015-01-02', '2015', '01', '02', index: 0, input: '2015-01-02' ]// ECMAScript 2018let re2 = /(?
\d{4})-(?
\d{2})-(?
\d{2})/u;let result2 = re2.exec('2015-01-02');console.log(result2);// ["2015-01-02", "2015", "01", "02", index: 0, input: "2015-01-02", // groups: {year: "2015", month: "01", day: "02"}// ]console.log(result2.groups.year); // 2015

4.2 在 regex 内使用 Named groups

使用\k<组名>格式来反向引用正则表达式本身中的组,例如:

图片描述

// 在下面的例子中,我们有一个包合的“水果”组。// 它既可以配“苹果”,也可以配“橘子”,// 我们可以使用 “\k
” (\k
) 来反向引用这个组的结果,// 所以它可以匹配“=”相同的单词let sameWords = /(?
apple|orange)=\k
/u;sameWords.test('apple=apple') // truesameWords.test('orange=orange') // truesameWords.test('apple=orange') // false

4.3 在 String.prototype.replace 中使用 named groups

在 String.prototype.replace 方法中使用 named groups。所以我们能更快捷的交换词。

例如,把 “firstName, lastName” 改成 “lastName, firstName”。

图片描述

let re = /(?
[A-Za-z]+) (?
[A-Za-z]+$)/u;'Hello World'.replace(re, `$
, $
`) // "World, Hello"

5.对象的 Rest 属性

rest操作 …(三个点)允许挑练我们需要的属性。

5.1 通过 Rest 解构你需要的属性

图片描述

let { firstName, age, ...remaining } = {  firstName: '王',  lastName: '智艺',  age: 27,  height: '1.78',  race: '黄'}firstName; // 王age; // 27remaining; // { lastName: "智艺", height: "1.78", race: "黄" }

6.对象的扩展属性

扩展 和 解析 的 三个点是一样的,但是不同的是你可以用 扩展 去新建或者组合一个新对象。

扩展 是对齐赋值的右运算符, 而
解构 是左运算符。

图片描述

const person = { fName: '小明', age: 20 };const account = { name: '小智', amount: '$1000'};const personAndAccount = { ...person, ...account };personAndAccount; // {fName: "小明", age: 20, name: "小智", amount: "$1000"}

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

断言(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)

你可以使用组(?<=…) 去正向断言,也可以用 (?<!…) 去取反。

正向断言: 我们想确保 # 在 winning 之前。(就是#winning),想正则匹配返回 winning。下面是写法:

图片描述

反向断言:匹配一个数字,有 € 字符而没有 $ 字符在前面的数字。

图片描述

更多内容可以参考:

用正则去匹配 Unicode 字符是很不容易的。像 w , W , d 这种只能匹配英文字符和数字。但是其他语言的字符怎么办呢,比如印度语,希腊语?

例如 Unicode 数据库组里把所有的印度语字符,标识为 Script = Devanagari。还有一个属性 Script_Extensions, 值也为 Devanagari。 所以我们可以通过搜索 Script=Devanagari,得到所有的印度语。

可以用于印度的各种语言,如Marathi, Hindi, Sanskrit。

在 ECMAScript 2018 里, 我们可以使用 p 和 {Script=Devanagari} 匹配那些所有的印度语字符。也就是说 p{Script=Devanagari} 这样就可以匹配。

图片描述

//The following matches multiple hindi character/^\p{Script=Devanagari}+$/u.test('हिन्दी'); //true  //PS:there are 3 hindi characters h

同理,希腊语的语言是 Script_Extensions 和 Script 的值等于 Greek 。也就是用Script_Extensions=Greek or Script=Greek 这样就可以匹配所有的希腊语,也就是说,我们用 p{Script=Greek} 匹配所有的希腊语。

进一步说,Unicode 表情库里存了各式各样的布尔值,像 Emoji, Emoji_Component, Emoji_Presentation, Emoji_Modifier, and Emoji_Modifier_Base 的值,都等于 true。所以我们想搜 Emoji 等于 ture,就能搜到所有的表情。

我们用 \p{Emoji} ,\Emoji_Modifier 匹配所有的表情。

图片描述

参考文献:

8. Promise.prototype.finally()

finally() 是 Promise 新增的一个实例方法。意图是允许在 resolve/reject 之后执行回调。finally 没有返回值,始终会被执行。

让我们看看各种情况。

图片描述

图片描述

图片描述

图片描述

9.异步迭代(Asynchronous Iteration)

这是一个极其好用的新特性。让我们能够非常容易的创建异步循环代码。

图片描述

原文:

你的点赞是我持续分享好东西的动力,欢迎点赞!

一个笨笨的码农,我的世界只能终身学习!

更多内容请关注公众号

转载地址:http://mdkpa.baihongyu.com/

你可能感兴趣的文章
pycharm多行批量缩进和反向缩进快捷键
查看>>
设计模式——外观模式(Facade)
查看>>
Sublime Text 2 使用心得
查看>>
SQLite数据库查询优化
查看>>
UIViewController各个方法的加载顺序
查看>>
Jenkins新建节点,启动方式没有“通过Java Web启动代理”选项怎么办?
查看>>
iOS html格式解析
查看>>
软件工程实践2017第一次作业
查看>>
Homestead 中使用 laravel-mix 问题汇总
查看>>
Selenium2Library系列 keywords 之 _SelectElementKeywords 之 unselect_from_list(self, locator, *items)...
查看>>
GNU/Linux 初学之旅(转)
查看>>
【java】Split函数踩坑记
查看>>
【leetcode】Decode Ways
查看>>
SLES documentation
查看>>
Python的metaclass、`__new()__`、单例模式
查看>>
在CentOS7上安装Zabbix3.0
查看>>
066、Weave如何与外网通信?(2019-04-09 周二)
查看>>
ASP常用函数
查看>>
tomcat绑定域名
查看>>
六数码问题(回溯)
查看>>