阿里云最近在作活动,低至2折,有兴趣能够看看:
https://promotion.aliyun.com/...
为了保证的可读性,本文采用意译而非直译。css
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!html
跟踪JavaScript (ECMAScript)中的新内容是很困难的,并且更难找到有用的代码示例。前端
所以,在本文中将介绍 TC39(最终草案) 在ES201六、ES2017和ES2018中添加的已完成提案中列出的全部18个特性,并给出有用的示例。git
include 是数组上的一个简单实例方法,能够轻松查找数组中是否有指定内容(包括 NaN)。github
像加法和减法这样的数学运算分别有像 + 和 - 这样运算符。与它们相似,**
运算符一般用于指数运算。在ECMAScript 2016中,引入了 **
代替 Math.pow。web
Object.values()是一个相似于Object.keys()的新函数,但返回对象自身属性的全部值,不包括原型链中的任何值。正则表达式
Object.entries()与Object.keys 相似,但它不是仅返回键,而是以数组方式返回键和值。 这使得在循环中使用对象或将对象转换为映射等操做变得很是简单。数据库
例一:segmentfault
例二:数组
在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=*=*=*=*='
当咱们想要在漂亮的打印显示或终端打印进行对齐时,这很是有用。
在下面的例子中,有一个不一样长度的数字列表。咱们但愿在“0”为追加符让全部项长度都为10位,以便显示,咱们可使用padStart(10, '0')轻松实现这一点。
当咱们打印多个不一样长度的项目并想要右对齐它们时,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
Emojis和其余双字节字符使用多个unicode字节表示。因此padStart padEnd可能不会像预期的那样工做!⚠️
例如:假设咱们要垫达到10个字符的字符串的心❤️emoji。结果以下:
'heart'.padStart(10, "❤️"); // prints.. '❤️❤️❤heart'
这是由于 ❤️ 长2个字节(' u2764 uFE0F')! 单词 heart 是5个字符,因此咱们只剩下5个字符来填充。 因此 JS 使用 ('u2764uFE0F' ) 填充两颗心并生成 ❤️❤️。 对于最后一个,它只使用 ('u2764uFE0F' ) 的第一个字节(u2764)来生成,因此是 ❤;
此方法返回给定对象的全部属性的全部属性(包括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 !
ES2017容许函数的最后一个参数有尾逗号(trailing comma), 此前,函数定义和调用时,都不容许最后一个参数后面出现逗号。这一变化将鼓励开发人员中止丑陋的“行以逗号开头”的习惯。这对于版本管理系统来讲,就会显示添加逗号的那一行也发生了变更。
到目前为止,我的感觉是这是最重要和最有用的功能。 async 函数容许咱们不处理回调地狱,并使整个代码看起来很简单。
async 关键字告诉 JavaScript 编译器以不一样的方式对待函数。每当编译器到达函数中的 await 关键字时,它就会暂停。它假定 wait 以后的表达式返回一个 promise ,并在进一步移动以前等待该 promise 被 resolved 或 rejected。
在下面的示例中,getAmount 函数调用两个异步函数getUser和getBankBalance。使用 async await更加优雅和简单达到有有序的调用 getUser 与 getBankBalance。
若是您正在等待 async 函数的结果,则须要使用 Promise 的 then 语法来捕获其结果。
在如下示例中,咱们但愿使用 console.log 来打印结果可是不在 doubleAndAdd 函数里面操做。 由于 async 返回是一个 promise 对象,因此能够在 then 里面执行咱们一些打印操做。
在前面的例子中,咱们调用doubleAfterlSec ,但每次咱们等待一秒钟(总共2秒)。 相反,咱们可使用 Promise.all 将它并行化为一个而且互不依赖于。
在使用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 引擎管理内存来编写高性能的并发程序。
这是经过一种名为 SharedArrayBuffer (即 共享数组缓冲区) 的新类型的全局对象实现的,该对象本质上是将数据存储在共享内存空间中。所以,这些数据能够在主JS线程和web工做线程之间共享。
到目前为止,若是咱们想在主 JS 线程和 web 工做者之间共享数据,咱们必须复制数据并使用postMessage 将其发送到另外一个线程。
你只需使用SharedArrayBuffer,数据就能够当即被主线程和多个web工做线程访问。workers 之间的协调变得更简单和更快(与 postMessage() 相比)。
可是在线程之间共享内存会致使竞争条件。为了帮助避免竞争条件,引入了 “Atomics” 全局对象。 Atomics 提供了各类方法来在线程使用其数据时锁定共享内存。 它还提供了安全地更新该共享内存中的搜索数据的方法。
若是你这对个感兴趣,能够阅读如下文章:
首先,咱们须要知道的什么是 Template literals(“标记的模板文字”),以便更好地理解这个特性。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 myTagFunc str // { cooked: "undefined", raw: "hi \\unicode" }
目前在正则表达式中,虽然点(“.”)应该匹配单个字符,但它不匹配像 n r f 等新行字符。
例如:
//Before /first.second/.test('first\nsecond'); //false
这种加强使 点 运算符可以匹配任何单个字符。为了确保它不会破坏任何东西,咱们须要在建立正则表达式时使用s标志。
//ECMAScript 2018 /first.second/s.test('first\nsecond'); //true Notice: /s 👈🏼
更多的方法,请看这里:
这种加强 RegExp特性借鉴于像Python、Java等其余语言,所以称为“命名组”。这个特性容许编写开发人员以(<name>…)格式为 RegExp 中的组的不一样部分提供名称(标识符),使用能够用这个名称轻松地获取他们须要的任何组。
在下面的示例中,咱们使用 (?<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 2018 let re2 = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\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
使用\k<组名>
格式来反向引用正则表达式自己中的组,例如:
// 在下面的例子中,咱们有一个包合的“水果”组。 // 它既能够配“苹果”,也能够配“橘子”, // 咱们可使用 “\k<group name>” (\k<fruit>) 来反向引用这个组的结果, // 因此它能够匹配“=”相同的单词 let sameWords = /(?<fruit>apple|orange)=\k<fruit>/u; sameWords.test('apple=apple') // true sameWords.test('orange=orange') // true sameWords.test('apple=orange') // false
在 String.prototype.replace 方法中使用 named groups。因此咱们能更快捷的交换词。
例如,把 “firstName, lastName” 改为 “lastName, firstName”。
let re = /(?<firstName>[A-Za-z]+) (?<lastName>[A-Za-z]+$)/u; 'Hello World'.replace(re, `$<lastName>, $<firstName>`) // "World, Hello"
rest操做 …(三个点)容许挑练咱们须要的属性。
let { firstName, age, ...remaining } = { firstName: '王', lastName: '智艺', age: 27, height: '1.78', race: '黄' } firstName; // 王 age; // 27 remaining; // { lastName: "智艺", height: "1.78", race: "黄" }
扩展 和 解析 的 三个点是同样的,可是不一样的是你能够用 扩展
去新建或者组合一个新对象。
扩展
是对齐赋值的右运算符, 而解构
是左运算符。
const person = { fName: '小明', age: 20 }; const account = { name: '小智', amount: '$1000'}; const personAndAccount = { ...person, ...account }; personAndAccount; // {fName: "小明", age: 20, name: "小智", amount: "$1000"}
断言(Assertion)是一个对当前匹配位置以前或以后的字符的测试, 它不会实际消耗任何字符,因此断言也被称为“非消耗性匹配”或“非获取匹配”。
正则表达式的断言一共有 4 种形式:
你可使用组(?<=…) 去正向断言,也能够用 (?<!…) 去取反。
正向断言: 咱们想确保 # 在 winning 以前。(就是#winning),想正则匹配返回 winning。下面是写法:
反向断言:匹配一个数字,有 € 字符而没有 $ 字符在前面的数字。
更多内容能够参考:S2018 新特征之:正则表达式反向(lookbehind)断言
用正则去匹配 Unicode 字符是很不容易的。像 w , W , d 这种只能匹配英文字符和数字。可是其余语言的字符怎么办呢,好比印度语,希腊语?
例如 Unicode 数据库组里把全部的印度语字符,标识为 Script = Devanagari。还有一个属性 Script_Extensions, 值也为 Devanagari。 因此咱们能够经过搜索 Script=Devanagari,获得全部的印度语。
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
匹配全部的表情。
参考文献:
finally()
是 Promise 新增的一个实例方法。意图是容许在 resolve/reject 以后执行回调。finally 没有返回值,始终会被执行。
让咱们看看各类状况。
这是一个极其好用的新特性。让咱们可以很是容易的建立异步循环代码。
原文: Here are examples of everything new in ECMAScript 2016, 2017, and 2018
你的点赞是我持续分享好东西的动力,欢迎点赞!
干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。
https://github.com/qq44924588...
我是小智,公众号「大迁世界」做者,对前端技术保持学习爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,便可看到福利,你懂的。