你可能错过的现代-JavaScript-特性

作者:Jimmy Breck-McKye翻译:疯狂的技术宅 原文:http://www.breck-mckye.com/bl... 未经允许严禁转载 尽管我在过去 7 年中几乎每天都在写 JavaScript 代码,但不得不承认,我实际上并不是很注意 ES 语言的发布声明。 async/await 和 Proxies 之类的主要特性是一回事,但是每年都有稳定的小规模、渐进式的改进在不断涌现,因为总有一些东西需要学习。 所以在本文中,我收集了一些现代 JavaScript 特性,这些特性在首次发布时并没有带来太多的关注。其中一些只是编码质量的提高,而另外一些确实很方便,可以减少很多代码量。以下是你可能会错过的一些信息: ES2015二进制和八进制在 JavaScript 中,二进制操作并不常见,但有时也会遇到,否则无法切实解决你的问题。你可能正在为低功耗设备编写高性能代码,将位压缩到本地存储中,在浏览器中进行像素 RGB 操作,或者必须处理紧密打包的二进制数据格式。 这可能意味着有很多工作需要对二进制数字进行处理,我一直觉得用十进制也能做这些事。好吧,ES6 为此添加了一个二进制数字格式:0b const binaryZero = 0b0;const binaryOne = 0b1;const binary255 = 0b11111111;const binaryLong = 0b111101011101101;这使得处理二进制标志非常容易: // Pizza toppingsconst olives = 0b0001;const ham = 0b0010;const pineapple = 0b0100;const artechoke = 0b1000;const pizza_ham_pineapple = pineapple | ham;const pizza_four_seasons = olives | ham | artechoke;对于八进制数也是如此。在 JS 世界中,这些领域有点小众,但在网络和某些文件格式中却很常见。现在你可以用语法 0o 处理八进制。 ...

November 5, 2019 · 2 min · jiezi

前端面试每日-31-第182天

今天的知识点 (2019.10.15) —— 第182天[html] 举例说明HTML5的标签meter的用法[css] 让你手写一个reset的文件,你应该怎么写?要考虑哪些方面呢?[js] 为什么说js是弱类型语言,它的优缺点分别是什么?[软技能] 你知道什么是ECMAScript吗?《论语》,曾子曰:“吾日三省吾身”(我每天多次反省自己)。 前端面试每日3+1题,以面试题来驱动学习,每天进步一点! 让努力成为一种习惯,让奋斗成为一种享受!相信 坚持 的力量!!!欢迎在 Issues 和朋友们一同讨论学习! 项目地址:前端面试每日3+1 【推荐】欢迎跟 jsliang 一起折腾前端,系统整理前端知识,目前正在折腾 LeetCode,打算打通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢迎大家前来讨论,如果觉得对你的学习有一定的帮助,欢迎点个Star, 同时欢迎微信扫码关注 前端剑解 公众号,并加入 “前端学习每日3+1” 微信群相互交流(点击公众号的菜单:进群交流)。 学习不打烊,充电加油只为遇到更好的自己,365天无节假日,每天早上5点纯手工发布面试题(死磕自己,愉悦大家)。希望大家在这浮夸的前端圈里,保持冷静,坚持每天花20分钟来学习与思考。在这千变万化,类库层出不穷的前端,建议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢迎大家到Issues交流,鼓励PR,感谢Star,大家有啥好的建议可以加我微信一起交流讨论!希望大家每日去学习与思考,这才达到来这里的目的!!!(不要为了谁而来,要为自己而来!)交流讨论欢迎大家前来讨论,如果觉得对你的学习有一定的帮助,欢迎点个[Star] https://github.com/haizlin/fe...

October 15, 2019 · 1 min · jiezi

工作中常用es6特性

结合工作中使用情况,简单对es6进行一些复习总结,包括常用的语法,api等,以及短时间内要上手需要重点学习的知识点(不同工作环境可能有一些差别),主要参考链接是阮一峰的博客以及外文博客(阮老师大部分文章是直接翻译的这个博客) http://2ality.com/p/about.html 1.简介先说一下ECMAScript,ECMA是一个标准化组织,他们制定了JavaScript的语言标准,所以之后一直称为ECMAScript,广泛的讲,Javascript是其一种标准实现,包括ECMAScript,dom,bom等 ECMA组织每年都会有新标准发布,标准名为ES+年份,所以我们会听到ES2015,ES2016,ES2017等,ES6其实就是ES2015,表示在15年发布的最新版本,相应的ES2016,ES2017分别称为ES7和ES8,依次往后对应。 现在大部分博客,文章,分享中提到的ES6其实也可以理解为ES6+,只不过因为2015年之前,ECMAScript有很多年没有发版(也有历史原因:ES4的夭折),积累了大量的新语法,api,所以在2015年一次性加在了ES6版本中发布,之后每年都只有很少的一些新增,比如: ES7: http://2ality.com/2016/01/ecm... (只有很少的两个属性)ES8:http://2ality.com/2016/02/ecm...…语法提案关于语法提案的流程,简单了解一下:一个新的语法从提案到成为标准需要经过五个阶段,每个阶段都需要标准委员会TC39定时开会进行批准 流程见链接:http://exploringjs.com/es2016... 需要注意的一点,所有的标准都是基于实现的,几大厂商浏览器对提案的实现必须先于标准才会进入定稿阶段,包括Babel 我们常用的async和await,就是因为16年开会的时候没有达到可定案的标准,而没有进入ES2016标准,最后添加在2017标准中 可参考该链接,有每年发布标准中新增的特性:http://2ality.com/2017/02/ecm... 2.简单知识点介绍下面主要就是结合平时工作,简单介绍最常用的语法,类方法以及实例方法等,下面主要是一些列举,大部分知识点想深入学习的话,还是得到阮老师博客或者外文博客上学习 不过我标注了实际工程中的使用频率,可以参考,针对性的学习,快速上手 提示:实际开发中结合eslint可以帮助自己写出更规范的代码使用频率极高(为方便一起介绍,会将一些不常用的语法也列出来,标题括号中也为大量使用): 2.1 let与const这是最基础的两个命令,都是声明变量,要强制所有的声明都使用他们两个 与var的区别: 作用域 var作用域在全局let与const作用域为代码块变量提升 (https://www.jianshu.com/p/68a...)暂时性死区,表示在一个块级作用域内,只要使用let声明一个变量,声明前将不能使用该变量不允许重复声明与顶层对象window或者global的关系,var声明的全局变量与顶层变量挂钩,而let const声明的全局变量不挂钩const与let区别: const定义一个只读的常量,一旦声明不可改变,但需要注意的是,不可改变的是变量指向的那个内存地址,如果使用const声明一个对象,对象内部是可以改变的,如果要强制一个对象不可改变,那么可以使用Object.freeze来冻结(该方法只冻结该对象,不会冻结其属性,所以可考虑递归)2.2 默认值设置我们可以直接在通过 param = 1 的形式设置默认值包括为函数参数设置,为解构设置(见下面介绍)避免了以前的这种写法: function test(data) { data = data || {}; ...}// 可以直接写为function test(data = {}) { ...}需要注意的是:默认值生效的条件是,严格等于 undefined,如果值为null,不会使用默认值2.3 解构赋值与rest操作符解构解构赋值其实就是为了更方便的从数组或者对象中通过属性名取数据,熟练使用之后,配合默认值,rest操作符可以很大程度提高效率,简化代码 下面是一些简单的使用对比 var a = 1, b = 2, c = 3;// 或者var param = { a: 1, b: 2, c: 3 };var a = param.a || 1; // 默认值var b = param.b;var c = param.c;// 或者function add(param) { param = param || {}; var v1 = param.v1 || 0; var v2 = param.v2 || 0; return v1 + v2;}可以看出来,如果参数比较多的话,代码很臃肿如果用解构赋值,我们可以写成这样,很简洁 ...

July 13, 2019 · 2 min · jiezi

asyncawait详解

1、简介需先了解 Promise 【链接地址】JavaScript 中的异步函数方法。JavaScript 在很短的时间内从回调演变为 Promises ,从 ES2017(ES8) 开始,使用 async/await 语法让异步 JavaScript 变得更简单。async(异步) 函数是 promises 和 generator 的组合,基本上,它们是对 promises 的更高级别的抽象。注意:async/await 基于 promises。2、引入 async/await 的原因它们降低了 promises 对一些固定语法样板的要求,打破了链式 promise “不能切断链式”的限制。在 ES2015 中引入 Promise 时,它们旨在解决异步代码的问题,并且他们确实做到了,但在 ES2015 和 ES2017 的两年中,人们发现很明显 promises 不是最终的解决方案。引入 Promises 来解决著名的回调地狱问题,但是因为他们自身的复杂性,引入了更复杂的语法。它们是良好的原语,可以向开发人员公开更好的语法,所以当时机成熟时,我们就有了 异步函数(async functions)。它们使代码看起来像是同步,但它在后台是异步和非阻塞的。2、原理async(异步) 函数返回一个 promise,如下例1所示: const doSomethingAsync = () => { return new Promise((resolve) => { setTimeout(() => resolve('I did something'), 3000) }) }3、未写完,待续

June 21, 2019 · 1 min · jiezi

每个JavaScript开发人员都应该知道的新ES2018功能(译文)

前言原文地址:https://css-tricks.com/new-es2018-features-every-javascript-developer-should-know/原文作者:Faraz Kelhini译者:Timbok翻译工具:Google Translate本文首发于我的个人网站: Timbok.top正文ECMAScript标准的第九版,官方称为ECMAScript 2018(或简称ES2018),于2018年6月发布。从ES2016开始,ECMAScript规范的新版本每年发布而不是每几年发布一次,并且添加的功能少于主要版本以前。该标准的最新版本通过添加四个新RegExp功能,rest/spread属性,asynchronous iteration,和Promise.prototype.finally。此外,ES2018从标记模板中删除了转义序列的语法限制。这些新变化将在后面的小节中解释。rest/spread属性ES2015最有趣的功能之一是点差运算符。该运算符使复制和合并数组变得更加简单。您可以使用运算符…,而不是调用concat()or slice()方法:const arr1 = [10, 20, 30];// make a copy of arr1const copy = […arr1];console.log(copy); // → [10, 20, 30]const arr2 = [40, 50];// merge arr2 with arr1const merge = […arr1, …arr2];console.log(merge); // → [10, 20, 30, 40, 50]在必须作为函数的单独参数传入数组的情况下,扩展运算符也派上用场。例如:const arr = [10, 20, 30]// equivalent to// console.log(Math.max(10, 20, 30));console.log(Math.max(…arr)); // → 30ES2018通过向对象文字添加扩展属性来进一步扩展此语法。使用spread属性,您可以将对象的自身可枚举属性复制到新对象上。请考虑以下示例:const obj1 = { a: 10, b: 20};const obj2 = { …obj1, c: 30};console.log(obj2); // → {a: 10, b: 20, c: 30}在此代码中,…运算符用于检索属性obj1并将其分配给obj2。在ES2018之前,尝试这样做会引发错误。如果有多个具有相同名称的属性,则将使用最后一个属性:const obj1 = { a: 10, b: 20};const obj2 = { …obj1, a: 30};console.log(obj2); // → {a: 30, b: 20}Spread属性还提供了一种合并两个或多个对象的新方法,可以将其用作方法的替代Object.assign()方法:const obj1 = {a: 10};const obj2 = {b: 20};const obj3 = {c: 30};// ES2018console.log({…obj1, …obj2, …obj3}); // → {a: 10, b: 20, c: 30}// ES2015console.log(Object.assign({}, obj1, obj2, obj3)); // → {a: 10, b: 20, c: 30}但请注意,spread属性并不总是产生相同的结果Object.assign()。请考虑以下代码:Object.defineProperty(Object.prototype, ‘a’, { set(value) { console.log(‘set called!’); }});const obj = {a: 10};console.log({…obj}); // → {a: 10}console.log(Object.assign({}, obj)); // → set called!// → {}在此代码中,该Object.assign()方法执行继承的setter属性。相反,传播属性完全忽略了setter。重要的是要记住,spread属性只复制可枚举的属性。在以下示例中,type属性不会显示在复制的对象中,因为其enumerable属性设置为false:const car = { color: ‘blue’};Object.defineProperty(car, ’type’, { value: ‘coupe’, enumerable: false});console.log({…car}); // → {color: “blue”}即使它们是可枚举的,也会忽略继承的属性:const car = { color: ‘blue’};const car2 = Object.create(car, { type: { value: ‘coupe’, enumerable: true, }});console.log(car2.color); // → blueconsole.log(car2.hasOwnProperty(‘color’)); // → falseconsole.log(car2.type); // → coupeconsole.log(car2.hasOwnProperty(’type’)); // → trueconsole.log({…car2}); // → {type: “coupe”}在此代码中,car2继承color属性car。因为spread属性只复制对象的自己的属性,color所以不包含在返回值中。请记住,spread属性只能生成对象的浅表副本。如果属性包含对象,则仅复制对象的引用:const obj = {x: {y: 10}};const copy1 = {…obj}; const copy2 = {…obj}; console.log(copy1.x === copy2.x); // → true这里copy1和copy2的x是指在内存中的同一对象,所以全等运算返回true。ES2015中添加的另一个有用功能是rest参数,它使JavaScript程序员可以使用它…来表示值作为数组。例如:const arr = [10, 20, 30];const [x, …rest] = arr;console.log(x); // → 10console.log(rest); // → [20, 30]这里,arr的第一个值被分配给对应的x,而剩余的元素被分配给rest变量。这种称为阵列解构的模式变得如此受欢迎,以至于Ecma技术委员会决定为对象带来类似的功能:const obj = { a: 10, b: 20, c: 30};const {a, …rest} = obj;console.log(a); // → 10console.log(rest); // → {b: 20, c: 30}此代码使用解构赋值中的其余属性将剩余的自身可枚举属性复制到新对象中。请注意,rest属性必须始终出现在对象的末尾,否则会引发错误:const obj = { a: 10, b: 20, c: 30};const {…rest, a} = obj; // → SyntaxError: Rest element must be last element还要记住,在对象中使用多个rest会导致错误,除非它们是嵌套的:const obj = { a: 10, b: { x: 20, y: 30, z: 40 }};const {b: {x, …rest1}, …rest2} = obj; // no errorconst {…rest, …rest2} = obj; // → SyntaxError: Rest element must be last elementSupport for Rest/SpreadChromeFirefoxSafariEdge605511.1NoChrome AndroidFirefox AndroidiOS SafariEdge MobileSamsung InternetAndroid Webview605511.3No8.260Node.js8.0.0(运行时需要加-harmony)8.3.0(完全支持)Asynchronous Iteration(异步迭代)迭代数据集是编程的重要部分。此前ES2015,提供的JavaScript语句如for,for…in和while,和方法map(),filter()以及forEach()都用于此目的。为了使程序员能够一次一个地处理集合中的元素,ES2015引入了迭代器接口。如果对象具有Symbol.iterator属性,则该对象是可迭代的。在ES2015中,字符串和集合对象(如Set,Map和Array)带有Symbol.iterator属性,因此可以迭代。以下代码给出了如何一次访问可迭代元素的示例:const arr = [10, 20, 30];const iterator = arrSymbol.iterator; console.log(iterator.next()); // → {value: 10, done: false}console.log(iterator.next()); // → {value: 20, done: false}console.log(iterator.next()); // → {value: 30, done: false}console.log(iterator.next()); // → {value: undefined, done: true}Symbol.iterator是一个众所周知的符号,指定一个返回迭代器的函数。与迭代器交互的主要方法是next()方法。此方法返回具有两个属性的对象:value和done。value属性为集合中下一个元素的值。done属性的值为true或false表示集合是否迭代完成。默认情况下,普通对象不可迭代,但如果在其上定义Symbol.iterator属性,则它可以变为可迭代,如下例所示:const collection = { a: 10, b: 20, c: 30, Symbol.iterator { const values = Object.keys(this); let i = 0; return { next: () => { return { value: this[values[i++]], done: i > values.length } } }; }};const iterator = collectionSymbol.iterator; console.log(iterator.next()); // → {value: 10, done: false}console.log(iterator.next()); // → {value: 20, done: false}console.log(iterator.next()); // → {value: 30, done: false}console.log(iterator.next()); // → {value: undefined, done: true}此对象是可迭代的,因为它定义了一个Symbol.iterator属性。迭代器使用该Object.keys()方法获取对象属性名称的数组,然后将其分配给values常量。它还定义了一个计数器变量i,并给它一个初始值0.当执行迭代器时,它返回一个包含next()方法的对象。每次调用next()方法时,它都返回一对{value, done},value保持集合中的下一个元素并done保持一个布尔值,指示迭代器是否已达到集合的需要。虽然这段代码完美无缺,但却不必要。使用生成器函数可以大大简化过程:const collection = { a: 10, b: 20, c: 30, [Symbol.iterator]: function * () { for (let key in this) { yield this[key]; } }};const iterator = collectionSymbol.iterator; console.log(iterator.next()); // → {value: 10, done: false}console.log(iterator.next()); // → {value: 20, done: false}console.log(iterator.next()); // → {value: 30, done: false}console.log(iterator.next()); // → {value: undefined, done: true}在这个生成器中,for…in循环用于枚举集合并产生每个属性的值。结果与前一个示例完全相同,但它大大缩短了。迭代器的缺点是它们不适合表示异步数据源。ES2018的补救解决方案是异步迭代器和异步迭代。异步迭代器与传统迭代器的不同之处在于,它不是以形式返回普通对象{value, done},而是返回履行的承诺{value, done}。异步迭代定义了一个返回异步迭代器的Symbol.asyncIterator方法(而不是Symbol.iterator)。一个例子让这个更清楚:const collection = { a: 10, b: 20, c: 30, Symbol.asyncIterator { const values = Object.keys(this); let i = 0; return { next: () => { return Promise.resolve({ value: this[values[i++]], done: i > values.length }); } }; }};const iterator = collectionSymbol.asyncIterator; console.log(iterator.next().then(result => { console.log(result); // → {value: 10, done: false}}));console.log(iterator.next().then(result => { console.log(result); // → {value: 20, done: false} }));console.log(iterator.next().then(result => { console.log(result); // → {value: 30, done: false} }));console.log(iterator.next().then(result => { console.log(result); // → {value: undefined, done: true} }));请注意,不可使用promises的迭代器来实现相同的结果。虽然普通的同步迭代器可以异步确定值,但它仍然需要同步确定done的状态。同样,您可以使用生成器函数简化过程,如下所示:const collection = { a: 10, b: 20, c: 30, [Symbol.asyncIterator]: async function * () { for (let key in this) { yield this[key]; } }};const iterator = collectionSymbol.asyncIterator; console.log(iterator.next().then(result => { console.log(result); // → {value: 10, done: false}}));console.log(iterator.next().then(result => { console.log(result); // → {value: 20, done: false} }));console.log(iterator.next().then(result => { console.log(result); // → {value: 30, done: false} }));console.log(iterator.next().then(result => { console.log(result); // → {value: undefined, done: true} }));通常,生成器函数返回带有next()方法的生成器对象。当调用next()时,它返回一个{value,done},其value属性保存了yield值。异步生成器执行相同的操作,除了它返回一个履行{value,done}的promise。迭代可迭代对象的一种简单方法是使用for…of语句,但是for…of不能与async iterables一起使用,因为value和done不是同步确定的。因此,ES2018提供了for…await…of。我们来看一个例子:const collection = { a: 10, b: 20, c: 30, [Symbol.asyncIterator]: async function * () { for (let key in this) { yield this[key]; } }};(async function () { for await (const x of collection) { console.log(x); }})();// logs:// → 10// → 20// → 30在此代码中,for…await…of语句隐式调用Symbol.asyncIterator集合对象上的方法以获取异步迭代器。每次循环时,都会调用迭代器的next()方法,它返回一个promise。一旦解析了promise,就会将结果对象的value属性读取到x变量中。循环继续,直到返回的对象的done属性值为true。请记住,该for…await…of语句仅在异步生成器和异步函数中有效。违反此规则会导致一个SyntaxError报错。next()方法可能会返回拒绝的promise。要优雅地处理被拒绝的promise,您可以将for…await…of语句包装在语句中try…catch,如下所示:const collection = { Symbol.asyncIterator { return { next: () => { return Promise.reject(new Error(‘Something went wrong.’)) } }; }};(async function() { try { for await (const value of collection) {} } catch (error) { console.log(‘Caught: ’ + error.message); }})();// logs:// → Caught: Something went wrong.Support for Asynchronous IteratorsChromeFirefoxSafariEdge635712NoChrome AndroidFirefox AndroidiOS SafariEdge MobileSamsung InternetAndroid Webview635712No8.263Node.js8.0.0(运行时需要加-harmony)8.3.0(完全支持)Promise.prototype.finallyES2018的另一个令人兴奋的补充是finally()方法。一些JavaScript库之前已经实现了类似的方法,这在许多情况下证明是有用的。这鼓励了Ecma技术委员会正式添加finally()到规范中。使用这个方法,程序员将能不管promise的结果如何,都能执行一个代码块。我们来看一个简单的例子:fetch(‘https://www.google.com’) .then((response) => { console.log(response.status); }) .catch((error) => { console.log(error); }) .finally(() => { document.querySelector(’#spinner’).style.display = ’none’; });finally()无论操作是否成功,当您需要在操作完成后进行一些清理时,该方法会派上用场。在此代码中,该finally()方法只是在获取和处理数据后隐藏加载微调器。代码不是在then()和catch()方法中复制最终逻辑,而是在promise被fulfilled或rejected后注册要执行的函数。你可以使用promise.then(func,func)而不是promise.finally(func)来实现相同的结果,但你必须在fulfillment处理程序和rejection处理程序中重复相同的代码,或者为它声明一个变量:fetch(‘https://www.google.com’) .then((response) => { console.log(response.status); }) .catch((error) => { console.log(error); }) .then(final, final);function final() { document.querySelector(’#spinner’).style.display = ’none’;}和then()和catch()一样,finally()方法总是返回一个promise,因此可以链接更多的方法。通常,您希望使用finally()作为最后一个链,但在某些情况下,例如在发出HTTP请求时,最好链接另一个catch()以处理finally()中可能发生的错误。Support for Promise.prototype.finallyChromeFirefoxSafariEdge635811.118Chrome AndroidFirefox AndroidiOS SafariEdge MobileSamsung InternetAndroid Webview635811.1No8.263Node.js10.0.0(完全支持)新的RegExp功能ES2018为该RegExp对象增加了四个新功能,进一步提高了JavaScript的字符串处理能力。这些功能如下:S(DOTALL)标志Named Capture Groups(命名捕获组)Lookbehind Assertions(后向断言)Unicode Property Escapes(Unicode属性转义)S(DOTALL)标志点(.)是正则表达式模式中的特殊字符,它匹配除换行符之外的任何字符,例如换行符(\n)或回车符(\r)。匹配所有字符(包括换行符)的解决方法是使用具有两个相反短字的字符类,例如[\d\D]。此字符类告诉正则表达式引擎找到一个数字(\d)或非数字(\D)的字符。因此,它匹配任何字符:console.log(/one[\d\D]two/.test(‘one\ntwo’)); // → trueES2018引入了一种模式,其中点可用于实现相同的结果。可以使用s标志在每个正则表达式的基础上激活此模式:console.log(/one.two/.test(‘one\ntwo’)); // → falseconsole.log(/one.two/s.test(‘one\ntwo’)); // → true使用标志来选择新行为的好处是向后兼容性。因此,使用点字符的现有正则表达式模式不受影响。Named Capture Groups(命名捕获组)在一些正则表达式模式中,使用数字来引用捕获组可能会令人困惑。例如,使用/(\d{4})-(\d{2})-(\d{2})/与日期匹配的正则表达式。由于美式英语中的日期符号与英式英语不同,因此很难知道哪个组指的是哪一天,哪个组指的是月份:const re = /(\d{4})-(\d{2})-(\d{2})/;const match= re.exec(‘2019-01-10’);console.log(match[0]); // → 2019-01-10console.log(match[1]); // → 2019console.log(match[2]); // → 01console.log(match[3]); // → 10ES2018引入了使用(?<name>…)语法的命名捕获组。因此,匹配日期的模式可以用不那么模糊的方式编写:const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;const match = re.exec(‘2019-01-10’);console.log(match.groups); // → {year: “2019”, month: “01”, day: “10”}console.log(match.groups.year); // → 2019console.log(match.groups.month); // → 01console.log(match.groups.day); // → 10您可以使用\k<name>语法在模式中稍后调用命名的捕获组。例如,要在句子中查找连续的重复单词,您可以使用/\b(?<dup>\w+)\s+\k<dup>\b/:const re = /\b(?<dup>\w+)\s+\k<dup>\b/;const match = re.exec(‘Get that that cat off the table!’); console.log(match.index); // → 4console.log(match[0]); // → that that要将命名的捕获组插入到方法的替换字符串中replace(),您需要使用$<name>构造。例如:const str = ‘red & blue’;console.log(str.replace(/(red) & (blue)/, ‘$2 & $1’)); // → blue & redconsole.log(str.replace(/(?<red>red) & (?<blue>blue)/, ‘$<blue> & $<red>’)); // → blue & redLookbehind Assertions(后向断言)ES2018为JavaScript带来了后向性断言,这些断言已经在其他正则表达式实现中可用多年。以前,JavaScript只支持超前断言。后向断言用表示(?<=…),并使您能够匹配基于模式之前的子字符串的模式。例如,如果要在不捕获货币符号的情况下以美元,英镑或欧元匹配产品的价格,则可以使用/(?<=$|£|)\d+(.\d*)?/:const re = /(?<=$|£|)\d+(.\d*)?/;console.log(re.exec(‘199’)); // → nullconsole.log(re.exec(’$199’)); // → [“199”, undefined, index: 1, input: “$199”, groups: undefined]console.log(re.exec(‘50’)); // → [“50”, undefined, index: 1, input: “50”, groups: undefined]还有一个lookbehind的否定版本,用(?<!…),只有当模式前面没有lookbehind中的模式时,负lookbehind才允许您匹配模式。例如,模式/(?<!un)available/匹配没有“un”前缀的可用词这段翻译的不好,放上原文There is also a negative version of lookbehind, which is denoted by (?<!…). A negative lookbehind allows you to match a pattern only if it is not preceded by the pattern within the lookbehind. For example, the pattern /(?<!un)available/ matches the word available if it does not have a “un” prefix:Unicode Property Escapes(Unicode属性转义)ES2018提供了一种称为Unicode属性转义的新类型转义序列,它在正则表达式中提供对完整Unicode的支持。假设您要在字符串中匹配Unicode字符㉛。虽然㉛被认为是一个数字,但是你不能将它与\d速记字符类匹配,因为它只支持ASCII [0-9]字符。另一方面,Unicode属性转义可用于匹配Unicode中的任何十进制数:const str = ‘㉛’;console.log(/\d/u.test(str)); // → falseconsole.log(/\p{Number}/u.test(str)); // → true同样,如果要匹配任何Unicode字母字符,你可以使用\p{Alphabetic}:const str = ‘’;console.log(/\p{Alphabetic}/u.test(str)); // → true// the \w shorthand cannot match console.log(/\w/u.test(str)); // → false还有一个否定版本\p{…},表示为\P{…}:console.log(/\P{Number}/u.test(‘㉛’)); // → falseconsole.log(/\P{Number}/u.test(’’)); // → trueconsole.log(/\P{Alphabetic}/u.test(‘㉛’)); // → trueconsole.log(/\P{Alphabetic}/u.test(’’)); // → false除了字母和数字之外,还有几个属性可以在Unicode属性转义中使用。您可以在当前规范提案中找到支持的Unicode属性列表。Support for New RegExp| Chrome | Firefox | Safari | EdgeS(DOTALL)标志62No11.1No命名捕获组64No11.1No后向断言62NoNoNoUnicode属性转义64No11.1No| Chrome Android | Firefox Android | iOS Safari | Edge Mobile | Samsung Internet | Android WebviewS(DOTALL)标志62No11.3No8.262命名捕获组64No11.3NoNo64后向断言62NoNoNo8.262Unicode属性转义64No11.3NoNo64Node.js8.3.0 (运行时需要加-harmony)8.10.0 (support for s (dotAll) flag and lookbehind assertions)10.0.0 (完全支持)模板字符串当模板字符串紧跟在表达式之后时,它被称为标记模板字符串。当您想要使用函数解析模板文字时,标记的模板会派上用场。请考虑以下示例:function fn(string, substitute) { if(substitute === ‘ES6’) { substitute = ‘ES2015’ } return substitute + string[1];}const version = ‘ES6’;const result = fn${version} was a major update;console.log(result); // → ES2015 was a major update在此代码中,调用标记表达式(它是常规函数)并传递模板文字。该函数只是修改字符串的动态部分并返回它。在ES2018之前,标记的模板字符串具有与转义序列相关的语法限制。反斜杠后跟某些字符序列被视为特殊字符:\x解释为十六进制转义符,\u解释为unicode转义符,\后跟一个数字解释为八进制转义符。其结果是,字符串,例如"C:\xxx\uuu"或者"\ubuntu"被认为是由解释无效转义序列,并会抛出SyntaxError。ES2018从标记模板中删除了这些限制,而不是抛出错误,表示无效的转义序列如下undefinedfunction fn(string, substitute) { console.log(substitute); // → escape sequences: console.log(string[1]); // → undefined}const str = ’escape sequences:’;const result = fn${str} \ubuntu C:\xxx\uuu;请记住,在常规模板文字中使用非法转义序列仍会导致错误:const result = \ubuntu;// → SyntaxError: Invalid Unicode escape sequenceSupport for Template Literal RevisionChromeFirefoxSafariEdge625611NoChrome AndroidFirefox AndroidiOS SafariEdge MobileSamsung InternetAndroid Webview625611No8.262Node.js8.3.0 (运行时需要加-harmony)8.10.0(完全支持)总结我们已经仔细研究了ES2018中引入的几个关键特性,包括异步迭代,rest/spread属性Promise.prototype.finally()以及RegExp对象的添加。虽然其中一些浏览器供应商尚未完全实现其中一些功能,但由于像Babel这样的JavaScript转换器,它们今天仍然可以使用。ECMAScript正在迅速发展,并且每隔一段时间就会引入新功能,因此请查看已完成提案的列表,了解新功能的全部内容。第一次翻译文章,能力有限,水平一般,翻译不妥之处,还望指正。感谢。 ...

January 15, 2019 · 6 min · jiezi

ECMAScript正则表达式6个最新特性

译者按: 还没学好ES6?ECMAScript 2018已经到来啦!原文:ECMAScript regular expressions are getting better!作者: Mathias Bynens: Google V8引擎开发者译者:Fundebug为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。1999年,ECMAScript 3添加了对正则表达式的支持。16年之后,ECMAScript 6(即ECMAScript 2015或者ES6)引入了Unicode模式(u选项), sticky模式(y选项)以及RegExp.prototype.flags的getter方法。这篇博客将介绍ECMAScript正则表达式的最新特性:dotAll模式(s选项)Lookbehind断言Named capture groupsUnicode property escapesString.prototype.matchAll规范RegExp遗留特性1. dotAll模式(s选项)这个特性已经在ECMAScript 2018正式发布了。默认情况下,.可以匹配任意字符,除了换行符:/foo.bar/u.test(‘foonbar’); // false另外,.不能匹配Unicode字符,需要使用u选项启用Unicode模式才行。ES2018引入了dotAll模式,通过s选项可以启用,这样,.就可以匹配换行符了。/foo.bar/su.test(‘foonbar’); // true2. Lookbehind断言这个特性已经在ECMAScript 2018正式发布了。ECMAScript目前仅支持lookahead断言。下面示例是Positive lookahead,匹配字符串“42 dollars”中紧跟着是"dollars"的数字:const pattern = /d+(?= dollars)/u;const result = pattern.exec(‘42 dollars’);console.log(result[0]); // 打印42下面示例是Negative lookahead,匹配字符串“42 pesos”中紧跟着的不是"dollars"的数字:const pattern = /d+(?! dollars)/u;const result = pattern.exec(‘42 pesos’);console.log(result[0]); // 打印42ES2018添加了lookbehind断言。下面示例是Positive lookbehind,匹配字符串“$42”中前面是"$“的数字:const pattern = /(?<=$)d+/u;const result = pattern.exec(’$42’);console.log(result[0]); // 打印42下面示例是Negative lookbehind,匹配字符串“$42”中前面不是是”$“的数字:const pattern = /(?<!$)d+/u;const result = pattern.exec(‘42’);console.log(result[0]); // 打印42Fundebug专注于网页、微信小程序、微信小游戏,支付宝小程序,React Native,Node.js和Java线上BUG实时监控,欢迎免费试用3. Named capture groups这个特性已经在ECMAScript 2018正式发布了。目前,正则表达式中小括号匹配的分组是通过数字编号的:const pattern = /(d{4})-(d{2})-(d{2})/u;const result = pattern.exec(‘2017-01-25’);console.log(result[0]); // 打印"2017-01-25"console.log(result[1]); // 打印"2017"console.log(result[2]); // 打印"01"console.log(result[3]); // 打印"25"这样很方便,但是可读性很差,且不易维护。一旦正则表达式中小括号的顺序有变化时,我们就需要更新对应的数字编号。ES2018添加named capture groups, 可以指定小括号中匹配内容的名称,这样可以提高代码的可读性,也便于维护。const pattern = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/u;const result = pattern.exec(‘2017-01-25’);console.log(result.groups.year); // 打印"2017"console.log(result.groups.month); // 打印"01"console.log(result.groups.day); // 打印"25"4. Unicode property escapes这个特性已经在ECMAScript 2018正式发布了。Unicode标准为每一个字符分配了多个属性。比如,当你要匹配希腊语字符时,则可以搜索Script_Extensions属性为Greek的字符。Unicode property escapes使得我们可以使用ECMAScript正则表达式直接匹配Unicode字符的属性:const regexGreekSymbol = /p{Script_Extensions=Greek}/u;console.log(regexGreekSymbol.test(’’)); // 打印true5. String.prototype.matchAll这个特性还处在Stage 3 Draftg和y选项通常用于匹配一个字符串,然后遍历所有匹配的子串,包括小括号匹配的分组。String.prototype.matchAll让这个操作变得更加简单了。const string = ‘Magic hex numbers: DEADBEEF CAFE 8BADF00D’;const regex = /b[0-9a-fA-F]+b/g;for (const match of string.matchAll(regex)) { console.log(match);}每一个迭代所返回的match对象与regex.exec(string)所返回的结果相同:// Iteration 1:[ ‘DEADBEEF’, index: 19, input: ‘Magic hex numbers: DEADBEEF CAFE 8BADF00D’]// Iteration 2:[ ‘CAFE’, index: 28, input: ‘Magic hex numbers: DEADBEEF CAFE 8BADF00D’]// Iteration 3:[ ‘8BADF00D’, index: 33, input: ‘Magic hex numbers: DEADBEEF CAFE 8BADF00D’]注意,这个特性还处在Stage 3 Draft,因此还存在变化的可能性,示例代码是根据最新的提案写的。另外,浏览器也还没有支持这个特性。String.prototype.matchAll最快可以被加入到ECMAScript 2019中。6. 规范RegExp遗留特性这个提案还处在Stage 3 Draft这个提案规范了RegExp的遗留特性,比如RegExp.prototype.compile方法以及它的静态属性从RegExp.&dollar;1到RegExp.&dollar;9。虽然这些特性已经弃用(deprecated)了,但是为了兼容性我们不能将他们去。因此,规范这些RegExp遗留特性是最好的方法。因此,这个提案有助于保证兼容性。参考阮一峰 - ECMAScript 6 入门Fundebug博客 - JavaScript正则表达式进阶指南ECMAScript 2018: the final feature set关于FundebugFundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了6亿+错误事件,得到了Google、360、金山软件等众多知名用户的认可。欢迎免费试用!版权声明:转载时请注明作者Fundebug以及本文地址:https://blog.fundebug.com/201… ...

August 30, 2018 · 1 min · jiezi