【第808期】你不懂JS:ES6与将来 语法(中)

图片

前言前端

又是一篇会让你们Mark的文章,今天继续连载《你不懂JS》系列,本文由前端早读课专栏做者@HetfieldJoe受权分享。正则表达式


正文从这开始~编程


语法(上)详见:【第798期】你不懂JS:ES6与将来 语法(上)数组


对象字面量扩展安全

ES6给不起眼儿的{ .. }对象字面量增长了几个重要的便利扩展。ide


简约属性函数

你必定很熟悉用这种形式的对象字面量声明:工具

图片


若是处处说x: x老是让你感到繁冗,那么有个好消息。若是你须要定义一个名称和词法标识符一致的属性,你能够将它从x: x缩写为x。考虑以下代码:oop

图片


简约方法this

本着与咱们刚刚检视的简约属性相同的精神,添附在对象字面量属性上的函数也有一种便利简约形式。


之前的方式:

图片


而在ES6中:

图片


警告: 虽然x() { .. }看起来只是x: function(){ .. }的缩写,可是简约方法有一种特殊行为,是它们对应的老方式所不具备的;确切地说,是容许super(参见本章稍后的“对象super”)的使用。


Generator(见第四章)也有一种简约方法形式:

图片


简约匿名

虽然这种便利缩写十分诱人,可是这其中有一个微妙的坑要当心。为了展现这一点,让咱们检视一下以下的前ES6代码,你可能会试着使用简约方法来重构它:

图片


这段蠢代码只是生成两个随机数,而后用大的减去小的。但这里重要的不是它作的是什么,而是它是如何被定义的。让我把焦点放在对象字面量和函数定义上,就像咱们在这里看到的:

图片

为何咱们同时说something:和function something?这不是冗余吗?实际上,不是,它们俩被用于不一样的目的。属性something让咱们可以调用o.something(..),有点儿像它的公有名称。可是第二个something是一个词法名称,使这个函数能够为了递归而从内部引用它本身。


你能看出来为何return something(y,x)这一行须要名称something来引用这个函数吗?由于这里没有对象的词法名称,要是有的话咱们就能够说return o.something(y,x)或者其余相似的东西。


当一个对象字面量的确拥有一个标识符名称时,这实际上是一个很常见的作法,好比:

图片

这是个好主意吗?也许是,也许不是。你在假设名称controller将老是指向目标对象。但它也极可能不是 —— 函数makeRequest(..)不能控制外部的代码,所以不能强制你的假设必定成立。这可能会回过头来咬到你。


另外一些人喜欢使用this定义这样的东西:

图片

这看起来不错,并且若是你老是用controller.makeRequest(..)来调用方法的话它就应该能工做。但如今你有一个this绑定的坑,若是你作这样的事情的话:

图片

固然,你能够经过传递controller.makeRequest.bind(controller)做为绑定到事件上的处理器引用来解决这个问题。可是这很讨厌 —— 它不是很吸引人。


或者要是你的内部this.makeRequest(..)调用须要从一个嵌套的函数内发起呢?你会有另外一个this绑定灾难,人们常用var self = this这种用黑科技解决,就像:

图片

更讨厌。


注意: 更多关于this绑定规则和陷阱的信息,参见本系列的 this与对象原型 的第一到二章。


好了,这些与简约方法有什么关系?回想一下咱们的something(..)方法定义:

图片

在这里的第二个something提供了一个超级便利的词法标识符,它老是指向函数本身,给了咱们一个可用于递归,事件绑定/解除等等的完美引用 —— 不用乱搞this或者使用不可靠的对象引用。


太好了!


那么,如今咱们试着将函数引用重构为这种ES6解约方法的形式:

图片

第一眼看上去不错,除了这个代码将会坏掉。return something(..)调用经不会找到something标识符,因此你会获得一个ReferenceError。噢,但为何?


上面的ES6代码段将会被翻译为:

图片


仔细看。你看出问题了吗?简约方法定义暗指something: function(x,y)。看到咱们依靠的第二个something是如何被省略的了吗?换句话说,简约方法暗指匿名函数表达式。


对,讨厌。


注意: 你可能认为在这里=>箭头函数是一个好的解决方案。可是它们也一样不够,由于它们也是匿名函数表达式。咱们将在本章稍后的“箭头函数”中讲解它们。


一个部分地补偿了这一点的消息是,咱们的简约函数something(x,y)将不会是彻底匿名的。参见第七章的“函数名”来了解ES6函数名称的推断规则。这不会在递归中帮到咱们,可是它至少在调试时有用处。


那么咱们怎样总结简约方法?它们简短又甜蜜,并且很方便。可是你应当仅在你永远不须要将它们用于递归或事件绑定/解除时使用它们。不然,就坚持使用你的老式something: function something(..)方法定义。


你的不少方法都将可能从简约方法定义中受益,这是个很是好的消息!只要当心几处未命名的灾难就好。


ES5 Getter/Setter

技术上讲,ES5定义了getter/setter字面形式,可是看起来它们没有被太多地使用,这主要是因为缺少转译器来处理这种新的语法(其实,它是ES5中加入的惟一的主要新语法)。因此虽然它不是一个ES6的新特性,咱们也将简单地复习一下这种形式,由于它可能会随着ES6的向前发展而变得有用得多。


考虑以下代码:

图片


这些getter和setter字面形式也能够出如今类中;参见第三章。


警告: 可能不太明显,可是setter字面量必须刚好有一个被声明的参数;省略它或罗列其余的参数都是不合法的语法。这个单独的必须参数 能够 使用解构和默认值(例如,set id({ id: v = 0 }) { .. }),可是收集/剩余...是不容许的(set id(...v) { .. })。


计算型属性名

你可能曾经遇到过像下面的代码段那样的状况,你的一个或多个属性名来自于某种表达式,所以你不能将它们放在对象字面量中:

图片


ES6为对象字面定义增长了一种语法,它容许你指定一个应当被计算的表达式,其结果就是被赋值属性名。考虑以下代码:

图片


任何合法的表达式均可以出如今位于对象字面定义的属性名位置的[ .. ]内部。


颇有可能,计算型属性名最常常与Symbol(咱们将在本章稍后的“Symbol”中讲解)一块儿使用,好比:

图片


Symbol.toStringTag是一个特殊的内建值,咱们使用[ .. ]语法求值获得,因此咱们能够将值"really cool thing"赋值给这个特殊的属性名。


计算型属性名还能够做为简约方法或简约generator的名称出现:

图片

设置[[Prototype]]

咱们不会在这里讲解原型的细节,因此关于它的更多信息,参见本系列的 this与对象原型。


有时候在你声明对象字面量的同时给它的[[Prototype]]赋值颇有用。下面的代码在一段时期内曾经是许多JS引擎的一种非标准扩展,可是在ES6中获得了标准化:

图片

o2是用一个对象字面量声明的,但它也被[[Prototype]]连接到了o1。这里的__proto__属性名还能够是一个字符串"__proto__",可是要注意它 不能 是一个计算型属性名的结果(参见前一节)。


客气点儿说,__proto__是有争议的。在ES6中,它看起来是一个最终被很勉强地标准化了的,几十年前的自主扩展功能。实际上,它属于ES6的“Annex B”,这一部分罗列了JS感受它仅仅为了兼容性的缘由,而不得不标准化的东西。


警告: 虽然我勉强赞同在一个对象字面定义中将__proto__做为一个键,但我绝对不赞同在对象属性形式中使用它,就像o.__proto__。这种形式既是一个getter也是一个setter(一样也是为了兼容性的缘由),但绝对存在更好的选择。更多信息参见本系列的 this与对象原型。


对于给一个既存的对象设置[[Prototype]],你可使用ES6的工具Object.setPrototypeOf(..)。考虑以下代码:

图片


注意: 咱们将在第六章中再次讨论Object。“Object.setPrototypeOf(..)静态函数”提供了关于Object.setPrototypeOf(..)的额外细节。另外参见“Object.assign(..)静态函数”来了解另外一种将o2原型关联到o1的形式。


对象super

super一般被认为是仅与类有关。然而,因为JS对象仅有原型而没有类的性质,super是一样有效的,并且在普通对象的简约方法中行为几乎同样。


考虑以下代码:

图片


警告: super仅在简约方法中容许使用,而不容许在普通的函数表达式属性中。并且它还仅容许使用super.XXX形式(属性/方法访问),而不是super()形式。


在方法o2.foo()中的super引用被静态地锁定在了o2,并且明确地说是o2的[[Prototype]]。这里的super基本上是Object.getPrototypeOf(o2) —— 显然被解析为o1 —— 这就是他如何找到并调用o1.foo()的。


关于super的完整细节,参见第三章的“类”。


模板字面量

在这一节的最开始,我将不得不呼唤这个ES6特性的极其……误导人的名称,这要看在你的经验中 模板(template) 一词的含义是什么。


许多开发者认为模板是一段可复用的,可重绘的文本,就像大多数模板引擎(Mustache,Handlebars,等等)提供的能力那样。ES6中使用的 模板 一词暗示着类似的东西,就像一种声明能够被重绘的内联模板字面量的方法。然而,这根本不是考虑这个特性的正确方式。


因此,在咱们继续以前,我把它重命名为它本应被称呼的名字:插值型字符串字面量(或者略称为 插值型字面量)。


你已经十分清楚地知道了如何使用"或'分隔符来声明字符串字面量,并且你还知道它们不是(像有些语言中拥有的)内容将被解析为插值表达式的 智能字符串。


可是,ES6引入了一种新型的字符串字面量,使用反引号`做为分隔符。这些字符串字面量容许嵌入基本的字符串插值表达式,以后这些表达式自动地被解析和求值。


这是老式的前ES6方式:

图片


如今,考虑这种新的ES6方式:

图片


如你所见,咱们在一系列被翻译为字符串字面量的字符周围使用了,可是${..}形式中的任何表达式都将当即内联地被解析和求值。称呼这样的解析和求值的高大上名词就是 插值(interpolation)(比模板要准确多了)。


被插值的字符串字面量表达式的结果只是一个老式的普通字符串,赋值给变量greeting。


警告: typeof greeting == "string"展现了为何不将这些实体考虑为特殊的模板值很重要,由于你不能将这种字面量的未求值形式赋值给某些东西并复用它。`..`字符串字面量在某种意义上更像是IIFE,由于它自动内联地被求值。`..`字符串字面量的结果只不过是一个简单的字符串。


插值型字符串字面量的一个真正的好处是他们容许被分割为多行:

image.png

在插值型字符串字面量中的换行将会被保留在字符串值中。


除非在字面量值中做为明确的转义序列出现,回车字符\r(编码点U+000D)的值或者回车+换行序列\r\n(编码点U+000D和U+000A)的值都会被泛化为一个换行字符\n(编码点U+000A)。但不要担忧;这种泛化不多见并且极可能仅会在你将文本拷贝粘贴到JS文件中时才会发生。


插值表达式

在一个插值型字符串字面量中,任何合法的表达式都被容许出如今${..}内部,包括函数调用,内联函数表达式调用,甚至是另外一个插值型字符串字面量!


考虑以下代码:

image.png


当咱们组合变量who与字符串s时, 相对于who + "s",这里的内部插值型字符串字面量`${who}s`更方便一些。有些状况下嵌套的插值型字符串字面量是有用的,可是若是你发现本身作这样的事情太频繁,或者发现你本身嵌套了好几层时,你就要当心一些。


若是确实有这样状况,你的字符串你值生产过程极可能能够从某些抽象中获益。


警告: 做为一个忠告,使用这样的新发现的力量时要很是当心你代码的可读性。就像默认值表达式和解构赋值表达式同样,仅仅由于你 能 作某些事情,并不意味着你 应该 作这些事情。在使用新的ES6技巧时千万不要作过了头,使你的代码比你或者你的其余队友聪明。


表达式做用域

关于做用域的一个快速提醒是它用于解析表达式中的变量时。我早先提到过一个插值型字符串字面量与IIFE有些相像,事实上这也能够考虑为做用域行为的一种解释。


考虑以下代码:

图片


在函数bar()内部,字符串字面量`..`被表达的那一刻,可供它查找的做用域发现变量的name的值为"bar"。既不是全局的name也不是foo(..)的name。换句话说,一个插值型字符串字面量在它出现的地方是词法做用域的,而不是任何方式的动态做用域。


标签型模板字面量

再次为了合理性而重命名这个特性:标签型字符串字面量。


老实说,这是一个ES6提供的更酷的特性。它可能看起来有点儿奇怪,并且也许一开始看起来通常不那么实用。但一旦你花些时间在它上面,标签型字符串字面量的用处可能会令你惊讶。


例如:

图片


让咱们花点儿时间考虑一下前面的代码段中发生了什么。首先,跳出来的最刺眼的东西就是foo`Everything...`;。它看起来不像是任何咱们曾经见过的东西。不是吗?


它实质上是一种不须要( .. )的特殊函数调用。标签 —— 在字符串字面量`..`以前的foo部分 —— 是一个应当被调用的函数的值。实际上,它能够是返回函数的任何表达式,甚至是一个返回另外一个函数的函数调用,就像:

image.png


可是看成为一个字符串字面量的标签时,函数foo(..)被传入了什么?


第一个参数值 —— 咱们称它为strings —— 是一个全部普通字符串的数组(全部被插值的表达式之间的东西)。咱们在strings数组中获得两个值:"Everything is "和"!"。


以后为了咱们示例的方便,咱们使用...收集/剩余操做符(见本章早先的“扩散/剩余”部分)将全部后续的参数值收集到一个称为values的数组中,虽然说你原本固然能够把它们留做参数strings后面单独的命名参数。


被收集进咱们的values数组中的参数值,就是在字符串字面量中发现的,已经被求过值的插值表达式的结果。因此在咱们的例子中values里惟一的元素显然就是awesome。


你能够将这两个数组考虑为:在values中的值本来是你拼接在stings的值之间的分隔符,并且若是你将全部的东西链接在一块儿,你就会获得完整的插值字符串值。


一个标签型字符串字面量像是一个在插值表达式被求值以后,可是在最终的字符串被编译以前的处理步骤,容许你在从字面量中产生字符串的过程当中进行更多的控制。


通常来讲,一个字符串字面连标签函数(在前面的代码段中是foo(..))应当计算一个恰当的字符串值并返回它,因此你可使用标签型字符串字面量做为一个未打标签的字符串字面量来使用:

image.png


在这个代码段中,tag(..)是一个直通操做,由于它不实施任何特殊的修改,而只是使用reduce(..)来循环遍历,并像一个未打标签的字符串字面量同样,将strings和values拼接/穿插在一块儿。


那么实际的用法是什么?有许多高级的用法超出了咱们要在这里讨论的范围。但这里有一个格式化美圆数字的简单想法(有些像基本的本地化):

image.png

若是在values数组中遇到一个number值,咱们就在它前面放一个"$"并用toFixed(2)将它格式化为小数点后两位有效。不然,咱们就不碰这个值而让它直经过去。


原始字符串

在前一个代码段中,咱们的标签函数接受的第一个参数值称为strings,是一个数组。可是有一点儿额外的数据被包含了进来:全部字符串的原始未处理版本。你可使用.raw属性访问这些原始字符串值,就像这样:

图片

原始版本的值保留了原始的转义序列\n(`和n`是两个分离的字符),但处理过的版本认为它是一个单独的换行符。可是,早先提到的行终结符泛化操做,是对两个值都实施的。


ES6带来了一个内建函数,它能够用作字符串字面量的标签:String.raw(..)。它简单地直通strings值的原始版本:

image.png

字符串字面量标签的其余用法包括国际化,本地化,和许多其余的特殊处理。


箭头函数

咱们在本章早先接触了函数中this绑定的复杂性,并且在本系列的 this与对象原型 中也以至关的篇幅讲解过。理解普通函数中基于this的编程带来的挫折是很重要的,由于这是ES6的新=>箭头函数的主要动机。


做为与普通函数的比较,咱们首先来展现一下箭头函数看起来什么样:

图片


箭头函数的定义由一个参数列表(零个或多个参数,若是参数不是只有一个,须要有一个( .. )包围这些参数)组成,紧跟着是一个=>符号,而后是一个函数体。


因此,在前面的代码段中,箭头函数只是(x,y) => x + y这一部分,而这个函数的引用恰好被赋值给了变量foo。


函数体仅在含有多于一个表达式,或者由一个非表达式语句组成时才须要用{ .. }括起来。若是仅含有一个表达式,并且你省略了外围的{ .. },那么在这个表达式前面就会有一个隐含的return,就像前面的代码段中展现的那样。


这里是一些其余种类的箭头函数:

图片

箭头函数 老是 函数表达式;不存在箭头函数声明。并且很明显它们都是匿名函数表达式 —— 它们没有能够用于递归或者事件绑定/解除的命名引用 —— 但在第七章的“函数名”中将会讲解为了调试的目的而存在的ES6函数名接口规则。


注意: 普通函数参数的全部功能对于箭头函数都是可用的,包括默认值,解构,剩余参数,等等。


箭头函数拥有漂亮,简短的语法,这使得它们在表面上看起来对于编写简洁代码颇有吸引力。确实,几乎全部关于ES6的文献(除了这个系列中的书目)看起来都当即将箭头函数仅仅认做“新函数”。

这说明在关于箭头函数的讨论中,几乎全部的例子都是简短的单语句工具,好比那些做为回调传递给各类工具的箭头函数。例如:

图片

在这些状况下,你的内联函数表达式很适合这种在一个单独语句中快速计算并返回结果的模式,对于更繁冗的function关键字和语法来讲箭头函数确实看起来是一个很吸人,并且轻量的替代品。


大多数人看着这样简洁的例子都倾向于发出“哦……!啊……!”的感叹,就像我想象中你刚刚作的那样!


然而我要警示你的是,在我看来,使用箭头函数的语法代替普通的,多语句函数,特别是那些能够被天然地表达为函数声明的函数,是某种误用。


回忆本章早前的字符串字面量标签函数dollabillsyall(..) —— 让咱们将它改成使用=>语法:图片


在这个例子中,我作的惟一修改是删除了function,return,和一些{ .. },而后插入了=>和一个var。这是对代码可读性的重大改进吗?呵呵。


实际上我会争论,缺乏return和外部的{ .. }在某种程度上模糊了这样的事实:reduce(..)调用是函数dollabillsyall(..)中惟一的语句,并且它的结果是这个调用的预期结果。另外,那些受过训练而习惯于在代码中搜索function关键字来寻找做用域边界的眼睛,如今须要搜索=>标志,在密集的代码中这绝对会更加困难。


虽然不是一个硬性规则,可是我要说从=>箭头函数转换得来的可读性,与被转换的函数长度成反比。函数越长,=>能帮的忙越少;函数越短,=>的闪光之处就越多。


我以为这样作更明智也更合理:在你须要短的内联函数表达式的地方采用=>,但保持你的通常长度的主函数原封不动。


不仅是简短的语法,而是this

曾经集中在=>上的大多数注意力都是它经过在你的代码中除去function,return,和{ .. }来节省那些宝贵的击键。


可是至此咱们一直忽略了一个重要的细节。我在这一节最开始的时候说过,=>函数与this绑定行为密切相关。事实上,=>箭头函数 主要的设计目的 就是以一种特定的方式改变this的行为,解决在this敏感的编码中的一个痛点。


节省击键是掩人耳目的东西,至可能是一个误导人的配角。


让咱们重温本章早前的另外一个例子:

图片


咱们使用了黑科技var self = this,而后引用了self.makeRequest(..),由于在咱们传递给addEventListener(..)的回调函数内部,this绑定将与makeRequest(..)自己中的this绑定不一样。换句话说,由于this绑定是动态的,咱们经过self变量退回到了可预测的词法做用域。


在这其中咱们终于能够看到=>箭头函数主要的设计特性了。在箭头函数内部,this绑定不是动态的,而是词法的。在前一个代码段中,若是咱们在回调里使用一个箭头函数,this将会不出所料地成为咱们但愿它成为的东西。


考虑以下代码:

图片

前面代码段的箭头函数中的词法this如今指向的值与外围的makeRequest(..)函数相同。换句话说,=>是var self = this的语法上的替代品。

在var self = this(或者,另外一种选择是,.bind(this)调用)一般能够帮忙的状况下,=>箭头函数是一个基于相同原则的很好的替代操做。听起来很棒,是吧?


没那么简单。


若是=>取代var self = this或.bind(this)能够工做,那么猜猜=>用于一个 不须要 var self = this就能工做的this敏感的函数会发生么?你可能会猜到它将会把事情搞砸。没错。

考虑以下代码:

图片

虽然咱们以controller.makeRequest(..)的方式进行了调用,可是this.helper引用失败了,由于这里的this没有像日常那样指向controller。那么它指向哪里?它经过词法继承了外围的做用域中的this。在前面的代码段中,它是全局做用域,this指向了全局做用域。呃。


除了词法的this之外,箭头函数还拥有词法的arguments —— 它们没有本身的arguments数组,而是从它们的上层继承下来 —— 一样还有词法的super和new.target(参见第三章的“类”)。


因此,关于=>在什么状况下合适或不合适,咱们如今能够推论出一组更加微妙的规则:


若是你有一个简短的,单语句内联函数表达式,它惟一的语句是某个计算后的值的return语句,而且 这个函数没有在它内部制造一个this引用,而且 没有自引用(递归,事件绑定/解除),而且 你合理地预期这个函数毫不会变得须要this引用或自引用,那么你就可能安全地将它重构为一个=>箭头函数。


若是你有一个内部函数表达式,它依赖于外围函数的var self = this黑科技或者.bind(this)调用来确保正确的this绑定,那么这个内部函数表达式就可能安全地变为一个=>箭头函数。


若是你有一个内部函数表达式,它依赖于外围函数的相似于var args = Array.prototype.slice.call(arguments)这样的东西来制造一个arguments的词法拷贝,那么这个内部函数就可能安全地变为一个=>箭头函数。


对于其余的全部东西 —— 普通函数声明,较长的多语句函数表达式,须要词法名称标识符进行自引用(递归等)的函数,和任何其余不符合前述性质的函数 —— 你就可能应当避免=>函数语法。


底线:=>与this,arguments,和super的词法绑定有关。它们是ES6为了修正一些常见的问题而被有意设计的特性,而不是为了修正bug,怪异的代码,或者错误。


不要相信任何说=>主要是,或者几乎是,为了减小几下击键的炒做。不管你是省下仍是浪费了这几下击键,你都应当确切地知道你打入的每一个字母是为了作什么。


提示: 若是你有一个函数,因为上述各类清楚的缘由而不适合成为一个=>箭头函数,但同时它又被声明为一个对象字面量的一部分,那么回想一下本章早先的“简约方法”,它有简短函数语法的另外一种选择。


对于如何/为什么选用一个箭头函数,若是你喜欢一个可视化的决策图的话:

图片


for..of Loops

伴随着咱们熟知的JavaScriptfor和for..in循环,ES6增长了一个for..of循环,它循环遍历一组由一个 迭代器(iterator) 产生的值。


你使用for..of循环遍历的值必须是一个 可迭代对象(iterable),或者它必须是一个能够被强制转换/封箱(参见本系列的 类型与文法)为一个可迭代对象的值。一个可迭代对象只不过是一个能够生成迭代器的对象,而后由循环使用这个迭代器。


让咱们比较for..of与for..in来展现它们的区别:

图片


如你所见,for..in循环遍历数组a中的键/索引,而for.of循环遍历a中的值。


这是前面代码段中for..of的前ES6版本:

图片


而这是一个ES6版本的非for..of等价物,它同时展现了手动迭代一个迭代器(见第三章的“迭代器”):

图片


在幕后,for..of循环向可迭代对象要来一个迭代器(使用内建的Symbol.iterator;参见第七章的“通用Symbols”),而后反复调用这个迭代器并将它产生的值赋值给循环迭代的变量。


在JavaScript标准的内建值中,默认为可迭代对象的(或提供可迭代能力的)有:

  • 数组

  • 字符串

  • Generators(见第三章)

  • 集合/类型化数组(见第五章)


警告: 普通对象默认是不适用于for..of循环的。由于他们没有默认的迭代器,这是有意为之的,不是一个错误。可是,咱们不会进一步探究这其中微妙的缘由。在第三章的“迭代器”中,咱们将看到如何为咱们本身的对象定义迭代器,这容许for..of遍历任何对象来获得咱们定义的一组值。


这是如何遍历一个基本类型的字符串中的字符:

图片


基本类型字符串"hello"被强制转换/封箱为等价的String对象包装器,它是默认就是一个可迭代对象。


在for (XYZ of ABC)..中,XYZ子句既能够是一个赋值表达式也能够是一个声明,这与for和for..in中相同的子句如出一辙。因此你能够作这样的事情:

image.png


与其余的循环同样,使用break,continue,return(若是是在一个函数中),以及抛出异常,for..of循环能够被提早终止。在任何这些状况下,迭代器的return(..)函数(若是存在的话)都会被自动调用,以便让迭代器进行必要的清理工做。


注意: 可迭代对象与迭代器的完整内容参见第三章的“迭代器”。


正则表达式

让咱们认可吧:长久以来在JS中正则表达式都没怎么改变过。因此一件很棒的事情是,在ES6中它们终于学会了一些新招数。咱们将在这里简要地讲解一下新增的功能,可是正则表达式总体的话题是如此厚重,以致于若是你须要复习一下的话你须要找一些关于它的专门章节/书籍(有许多!)。


Unicode标志

咱们将在本章稍后的“Unicode”一节中讲解关于Unicode的更多细节。在此,咱们将仅仅简要地看一下ES6+正则表达式的新u标志,它使这个正则表达式的Unicode匹配成为可能。


JavaScript字符串一般被解释为16位字符的序列,它们对应于 基本多文种平面(Basic Multilingual Plane (BMP)) (http://en.wikipedia.org/wiki/Plane_%28Unicode%29)中的字符。可是有许多UTF-16字符在这个范围之外,并且字符串可能含有这些多字节字符。


在ES6以前,正则表达式只能基于BMP字符进行匹配,这意味着在匹配时那些扩展字符被看做是两个分离的字符。这一般不理想。


因此,在ES6中,u标志告诉正则表达式使用Unicode(UTF-16)字符的解释方式来处理字符串,这样一来一个扩展的字符将做为一个单独的实体被匹配。


警告: 尽管名字的暗示是这样,可是“UTF-16”并不严格地意味着16位。现代的Unicode使用21位,并且像UTF-8和UTF-16这样的标准大致上是指有多少位用于表示一个字符。


一个例子(直接从ES6语言规范中拿来的):

相关文章
相关标签/搜索