原文做者:Faraz Kelhinijavascript
译者:UC 国际研发 Jothycss
写在最前:欢迎你来到“UC国际技术”公众号,咱们将为你们提供与客户端、服务端、算法、测试、数据、前端等相关的高质量技术文章,不限于原创与翻译。前端
编者按:曾几什么时候,年少的我捧着阮一峰老师的《ES6 标准入门》,感叹 JS 变迁实在太快,好怕学不动了。直至写了几年 ES6 的今日,回头看方知:不要为了学 ES X 而学 ES X,不管 ES 几其实都是语法糖,是辅助角色,重点是想清楚它能为咱们的开发带来什么好处,而不是本末倒置。今天介绍的 ES2018 新特性仍是有蛮多亮点的,一块儿来看看吧。java
ECMAScript 标准的第九版,官宣为 ECMAScript 2018(或简称 ES2018),已于 2018 年 6 月发布。从 ES2016 开始,每隔一年就会发布一版 ECMAScript 规范的新版本,并添加很少于主版本的功能。 最新的这个版本延续了每一年发布的周期,新增了四个新的 RegExp
特性,rest/spread 属性,异步迭代和 Promise.prototype.finally
。 此外,它还从标记模板中删除了转义序列的语法限制。
git
咱们将在后面的小节中详细解释这些新变化 😉。程序员
回顾 ES2015,最有趣的功能当数 spread 运算符。 该运算符极大简化了数组的复制及合并。你可使用它替换concat()
或slice()
方法:github
在必须将数组的各个项分别做为参数传入函数的状况下,扩展运算符也派得上用场。 例如:正则表达式
经过向对象文法添加 spread 属性,ES2018 进一步扩展了此语法。 使用 spread 属性,你能够将对象自身的可枚举属性复制到新对象上。举个例子 🌰:算法
在此代码中,...
运算符用于检索 obj1 的属性并将它们分配给 obj2。 在 ES2018 以前,这么作会报错的。 若是出现多个属性同名的状况,将会取最后一个值:编程
Spread 属性还提供了一种合并两个或多个对象的新方法,能够替代 Object.assign()
方法使用:
在此代码中,Object.assign()
方法会执行其继承的 setter 属性,而 spread 属性则彻底忽略了这一步。
切记!spread 属性只复制可枚举属性。 在下面的例子中,type
属性不会出如今复制出的对象中,由于其enumerable
属性为 false
:
继承属性即便是可枚举的,也会被忽略:
在这段代码中,car2
继承了car
的color
属性。 因为 spread 仅复制对象自身的属性,所以返回值中不包含 color
属性。
请记住,spread 只是对象的浅复制。 若是属性中包含对象,则仅复制对象的引用:
copy1
中的 x
属性与copy2
中的x
属性引用了内存中同一个对象,所以严格等于(strict equality)运算符返回 true.
ES2015 新增的另外一有用功能是 rest 参数,它使 JavaScript程序员可以使用...
将值表示为数组。 例如:
arr
的第一项被赋值给 x,剩下的被赋值给 rest
变量。 这种名为数组解构的模式很是受欢迎,以致于 Ecma 技术委员会(Ecma Technical Committee)决定为对象带来相似的功能:
此代码使用 rest 属性解构赋值,将对象 obj
剩余的自身可枚举属性复制到新对象rest
中。 须要引发注意的是,rest 属性必须始终位于对象的末尾,不然会报错:
此外,在对象中使用多个 rest 语法也会报错,除非它们是嵌套使用的:
8.0.0(须要 --harmony 运行时 flag)
8.3.0(彻底支持)
迭代数据集是编程的重要组成部分。 在 ES2015 以前,JavaScript提供了for
,for...in
和 while
等语句,以及map()
,filter()
和 forEach()
等方法。 为了方便程序员一个个地处理集合元素,ES2015 引入了迭代器接口。
若是对象具备 Symbol.iterator
属性,则表示它是可迭代的。 在 ES2015 中,字符串和集合对象(如Set
, Map
和 Array
)带有Symbol.iterator
属性,所以是可迭代的。 如下代码说明了如何每次访问一个可迭代元素☝️:
Symbol.iterator
是个广为人知的符号,用于表示返回迭代器的函数。与迭代器交互主要使用next()
方法。此方法返回一个具备value
和done
两个属性的对象。 value
属性包含集合中下一个元素的值。done
属性包含true
或false
,代表是否已到达集合的末尾。
默认状况下普通对象不可迭代,但若是在其上定义了 Symbol.iterator
属性,则它可变为可迭代对象,以下所示:
collection
对象是可迭代的,由于它定义了 Symbol.iterator
属性。 iterator 使用 Object.keys()
方法获取对象属性名的数组,而后将其赋值给常量values
.它还定义了一个计数器变量i
,初始值为 0. 当执行迭代器时,它返回一个包含 next()
方法的对象。 每次调用 next()
方法时,它都返回一个 {value, done}
键值对,其中 value
保存集合中的下一个元素,done
保存一个布尔值,表示迭代器是否已达到集合的末尾。
虽然以上代码运行完美,但它本无需如此复杂。 所幸,生成器( generator )函数能够大大简化该过程:
在今生成器中,for...in
循环用于枚举集合,yield 每一个属性的值。 结果与前一个示例彻底相同,但代码量大大减小。
迭代器的缺点是它们不适合表示异步数据源。 ES2018 的补救方案是异步迭代器(asynchronous iterators)和异步可迭代对象(asynchronous iterables)。 异步迭代器与传统迭代器的不一样点在于,它不返回 {value,done}
的形式的普通对象,而是返回一个完成(fulfill) {value,done}
的promise
.异步可迭代对象定义了一个返回异步迭代器的 Symbol.asyncIterator
方法(注意不是 Symbol.iterator
)。
举个例子🌰可能更清楚些:
请注意,使用 promises 的迭代器不可能达到相同的结果。 虽然普通的同步迭代器能够异步产生肯定值,但它仍然须要同步肯定“完成(done)”的状态。
一样,你可使用生成器函数简化此过程,以下所示:
一般生成器函数会返回带有next()
方法的生成器对象。 当调用 next()
时,它返回一个 {value,done}
键值对,其 value
属性保存了yield 的值。 异步生成器与之相似,只不过它返回的是一个完成了 {value,done}
的promise.
使用 for...of
语句能够轻松迭代可迭代对象,可是 for...of
不能与异步可迭代对象一块儿使用,由于 value
和 done
不是同步产生的。 出于这个缘由,ES2018 提供了 for...await...of
语句。 咱们来看一个例子:
在此代码中, for...await...of
语句隐式调用集合对象上的Symbol.asyncIterator
方法以获取异步迭代器。 每次循环时,都会调用迭代器的 next()
方法,该方法返回一个 promise. 一旦 promise 完成,就会将结果对象的 value
属性读取到x
变量。 循环继续,直到返回对象的 done
属性值为true
.
敲黑板!for...await...of
语句仅在异步生成器和异步函数中有效。 违反此规则会报 SyntaxError(语法错误)。
next()
方法可能会返回 rejected promise. 为了优雅地处理被 reject 的 promise,你可使用try...catch
语句包裹for...await...of
语句,以下所示:
8.10.0(须要 --harmony_async_iteration flag)
10.0.0(彻底支持)
ES2018另外一振奋人心的特效是finally()
方法。 以前有几个 JavaScript 库实现了相似的方法,而且它被证明是有用的。这促使 Ecma技术委员会正式将finally()
添加到规范中。 使用该方法,开发者可无需理会 promise 命数如何,直接执行这个代码块中的代码。 咱们来看一个简单的例子:
finally()
方法可在操做完成后进行一些扫尾(clean up)工做,不管操做是否成功。 在此代码中,finally()
方法在数据获取处理后直接隐藏了加载 spinner。 不管 promise 完成与否,函数中的注册代码都会执行,开发者没必要在 then()
和 catch()
方法中重复编写逻辑。
使用promise.then(func, func)
也可实现与promise.then(func, func)
一样的效果,但你必须在 fulfillment 句柄及 rejection 句柄中重复相同的代码,或者引入一个变量:
与 then()
和 catch()
相同,finally()
方法老是返回一个 promise,所以你能够连接更多的方法。 通常来讲,咱们会将 finally()
做为最后一环。但某些状况,例如在建立 HTTP 请求时,在 finally()
以后连接另外一个catch()
,以处理请求中可能发生的错误是不错的实践。
Node.js:
10.0.0(彻底支持)
ES2018 为 RegExp
对象增长了四个新特性,进一步提升了 JavaScript 的字符串处理能力。 这些特性以下:
s(dotAll)标志
可命名捕获组
Lookbehind断言
Unicode 属性转义
点(.)是正则表达式模式中的特殊字符,它匹配除换行符以外的任何字符,例如换行符(\n
)或回车符(\r
)。要匹配包括换行符在内的全部字符,解决方法是使用两个相反短字的字符类,例如[\d\D]
. 此字符类告诉正则表达式引擎找到一个数字(\d
)或非数字(\D
)的字符。 所以,它匹配任意字符:
ES2018 引入了一种模式,其中点可用于实现相同的结果。可使用s
标志在每一个正则表达式的基础上激活此模式:
利用标志来选择性使用新特性的好处是向后兼容,保证使用点字符的现有正则表达式模式不受影响。
在一些正则表达式模式中,使用数字来引用捕获组可能会形成混淆。 例如,采用正则表达式 /(\d{4})-(\d{2})-(\d{2})/
匹配日期。 因为美式英语中的日期符号与英式英语不一样,所以很难知道哪一个组指的是日,哪一个组指的是月:
ES2018 引入了使用(?<name>...)
语法的命名捕获组。 所以,匹配日期的模式能够用不太模糊的方式编写:
你可使用 \k<name>
语法在模式中再次调用命名捕获组。 例如,要查找句子中连续的重复单词,可使用 /\b(?<dup>\w+)\s+\k<dup>\b/
:
要将命名捕获组用于 replace()
方法的替换字符串,你可使用 $<name>
构造。 例如:
ES2018 为 JavaScript 带来了后行断言(lookbehind assertion),该断言已在其余语言的正则表达式使用多年。 之前,JavaScript 只支持先行断言(lookahead assertion)。 后行断言用 (?<=...)
表示,使你可以根据模式以前的子字符串匹配模式。 例如,若是你想要在不捕获货币符号的状况下以美圆,英镑或欧元匹配产品的价格,你可使用/(?<=\$|£|€)\d+(\.\d*)?/
:
还有一个负向的后行断言,用 (?<!...)
表示。 负向后行断言容许你匹配不跟在某后行断言以后的模式(译者注:差点把我本身都绕晕了😷 举个简单的例子(?<!a)b
: 断言 b 前面没有 a,匹配 bb 但不匹配 ab,最终捕获 b)。 例如,模式 /(?<!un)available/
可在无 “un” 前缀的状况下匹配 available:
ES2018 提供了一种称为 Unicode 属性转义的新转义序列类型,它在正则表达式中提供对完整 Unicode 的支持。 假设你要匹配字符串中的 Unicode 字符 ㉛. 虽然咱们认为 ㉛ 是一个数字,可是咱们不能用 \d
匹配它,由于它只支持 ASCII [0-9] 字符。此外,Unicode 属性转义也可用于匹配 Unicode 中的任何十进制数:
一样,若是要匹配任意 Unicode 单词(划掉)字母字符,可使用 \p{Alphabetic}
:
还有一个否认版本的\p{...}
,用\P{...}
,表示:
除了字母和数字以外,还有几个属性能够在 Unicode 属性转义中使用。 你能够在当前规范提案中找到支持的 Unicode 属性列表。
地址:https://tc39.github.io/proposal-regexp-unicode-property-escapes/#sec-static-semantics-unicodematchproperty-p
8.3.0(须要 --harmony 运行时 flag)
8.10.0(支持 s(dotAll) 标志和后行断言)
10.0.0(彻底支持)
当模板字符串紧跟在表达式以后时,它会被称为标记模板字符串。 当你想要使用函数解析模板字符串时,标记模板会派上用场。 看看这个例子:
上面的代码调用了标记表达式(它是常规函数)并传递模板字符串。 该函数只是修改字符串的动态部分并返回它。
在 ES2018 以前,标记的模板字符串具备与转义序列相关的语法限制。 反斜杠后跟某些字符序列被视为特殊字符:\x
被解析为十六进制转义符,\u
被解析为unicode转义符,\_
后跟一个数字被解析为八进制转义符。 所以,解释器将诸如 "C:\xxx\uuu"
或 "\ubuntu"
之类的字符串视为无效的转义序列,并将抛出SyntaxError
.
ES2018 从标记模板中删除了这些限制,它会将无效转义序列表示为 undefined
,而不是抛出错误:
请记住,在常规模板字符串中使用非法转义序列仍会报错:
8.3.0 (须要 --harmony 运行时 flag)
8.10.0(彻底支持)
咱们已经仔细研究了 ES2018 中引入的几个关键特性,包括异步迭代,rest/spread 属性,Promise.prototype.finally
以及 RegExp
对象的新增特性。 虽然有些浏览器厂商还没有彻底实现其中一些功能,但因为有 Babel 这样的 JavaScript 转换器,咱们仍能够在今天使用它们。
ECMAScript 正在迅速发展,而且每隔一段时间就会引入新功能,欢迎查看完整提案列表👏,了解所有新功能。 有啥功能让你特别兴奋吗?快快和我分享叭~
提案地址:https://github.com/tc39/proposals/blob/master/finished-proposals.md
原文地址:https://css-tricks.com/new-es2018-features-every-javascript-developer-should-know/
好文推荐:
“UC国际技术”致力于与你共享高质量的技术文章
欢迎关注咱们的公众号、将文章分享给你的好友