JavaScript指南第8部分:ES6功能概述

今天,在JavaScript手册翻译的第八部分中,我们将回顾ES6标准发布后出现在其中的语言的功能。 一种或另一种方式是,我们较早地遇到了许多此类机会,其中更详细地介绍了这些机会,而某些地方则视为理所当然。 本指南的这一部分旨在与我们之前未涉及的一些主题的公开内容一起,以简化现代JavaScript领域中新手开发人员的知识。

第1部分:第一个程序,语言功能,标准
第2部分:代码样式和程序结构
第3部分:变量,数据类型,表达式,对象
第4部分:功能
第5部分:数组和循环
第6部分:异常,分号,通配符文字
第7部分:严格模式,此关键字,事件,模块,数学计算
第8部分:ES6功能概述
第9部分:ES7,ES8和ES9标准概述



关于ES6


ES6标准可以更正确地称为ES2015或ECMAScript 2015(这些是其官方名称,尽管每个人都称其为ES6),它在前一个标准ES5.1发行4年后才出现。 开发进入ES5.1标准的所有内容大约花了十年时间。 如今,此标准中出现的所有内容都已成为JS开发人员的常用工具。 应当指出,ES6对语言进行了重大更改(同时保持了与以前版本的向后兼容性)。 为了理解这些变化的严重性,可以注意到描述ES5标准的文档的大小约为250页,而标准ES6在已经约600页的文档中进行了描述。

ES2015标准最重要的创新列表可以包括以下内容:

  • 箭头功能
  • 承诺
  • 发电机
  • 关键字letconst
  • 班级
  • 模组
  • 模板文字支持
  • 支持默认功能参数
  • 点差运算符
  • 破坏性分配
  • 增强对象文字
  • for...of循环
  • 支持MapSet数据结构

考虑这些可能性。

箭头功能


箭头功能改变了JavaScript代码的外观。 就外观而言,它们的使用使函数声明更短,更容易。 这是一个常规函数的声明。

 const foo = function foo() { //... } 

但是箭头功能几乎相同(尽管与上面并不完全相似)。

 const foo = () => { //... } 

如果箭头函数的主体仅包含一行,则必须从该函数返回其结果,那么它的编写会更短。

 const foo = () => doSomething() 

如果箭头功能仅使用一个参数,则可以按如下所示编写它。

 const foo = param => doSomething(param) 

应当指出,随着箭头功能的出现,普通功能并未消失,它们仍然可以在代码中使用,它们的工作方式与以前相同。

箭头功能中的此关键字功能


箭头函数没有自己的this值;它们从执行上下文继承它。

这解决了这个问题,为此,在使用常规函数时,必须使用诸如var that = this来保留上下文。 但是,如本手册前面的部分所示,此更改严重影响了使用箭头功能的功能及其应用范围。

承诺


承诺使您摆脱称为“回调地狱”的众所周知的问题,尽管它们的使用暗示使用相当复杂的结构。 在ES2017标准中,基于Promise的async/await构造的出现解决了此问题。

JavaScript开发人员在ES2015标准出现之前就使用了promise,为此使用了各种库(例如jQuery,q,deferred.js,誓言)。 这表明了该机制的重要性和相关性。 不同的库以不同的方式实现它,在这一领域中标准的出现可以认为是一个非常积极的事实。
这是使用回调函数(回调)编写的代码。

 setTimeout(function() { console.log('I promised to run after 1s') setTimeout(function() {   console.log('I promised to run after 2s') }, 1000) }, 1000) 

使用promise,可以将其重写如下。

 const wait = () => new Promise((resolve, reject) => { setTimeout(resolve, 1000) }) wait().then(() => { console.log('I promised to run after 1s') return wait() }) .then(() => console.log('I promised to run after 2s')) 

发电机


生成器是特殊功能,可以暂停其执行并继续执行。 这允许在生成器空闲时执行另一个代码。

生成器自行决定需要暂停并允许另一个“等待”的代码执行。 同时,生成器有机会在其等待结果的操作完成后继续执行。

这一切都归功于一个简单的关键字yield 。 在生成器中找到此关键字后,其执行将暂停。
生成器可以使用此关键字包含许多行,从而多次暂停其执行。 生成器使用*function构造进行声明。 对于诸如C,C ++或Go之类的语言中使用的指针解引用运算符之类的东西,不应在单词function前使用星号。

生成器标志着新的JavaScript编程范例的出现。 特别是,它们允许在生成器和其他代码之间进行双向数据交换,并允许创建不会“挂起”程序的长寿命while循环。

考虑一个示例,说明发电机运行的特征。 这是发电机本身。

 function *calculator(input) {   var doubleThat = 2 * (yield (input / 2))   var another = yield (doubleThat)   return (input * doubleThat * another) } 

使用此命令,我们对其进行初始化。

 const calc = calculator(10) 

然后我们转向它的迭代器。

 calc.next() 

该命令启动迭代器,它返回这样的对象。

 { done: false value: 5 } 

在这里发生以下情况。 该代码使用传递给生成器构造函数的input值执行函数。 执行生成器代码,直到在其中找到yield关键字为止。 此时,它返回将input除以2的结果,由于input10 ,因此得出数字5 。 由于有了迭代器,我们得到了这个数字,并伴随着它表明生成器尚未完成(迭代器返回的对象中的done属性设置为false ),也就是说,该函数仅被暂停了。
下次调用迭代器时,我们将数字7传递给生成器。

 calc.next(7) 

响应于此,迭代器将下一个对象返回给我们。

 { done: false value: 14 } 

在这里,数字7用于计算doubleThat值。

乍一看, input / 2代码似乎有点像某个函数的参数,但这只是第一次迭代时返回的值。 在这里,我们跳过此值,并使用新的输入值7乘以2 。 之后,我们获得第二个yield关键字,结果,第二次迭代中获得的值为14

在下一次迭代(即最后一次迭代)中,我们将数字100传递给生成器。

 calc.next(100) 

作为响应,我们得到以下对象。

 { done: true value: 14000 } 

迭代完成(在生成器中不再找到yield关键字),在对象中返回计算表达式(input * doubleThat * another)的结果,即10 * 14 * 100并指示迭代器已完成( done: true )。

关键字let和const


JavaScript一直使用var关键字来声明变量。 这样的变量具有功能范围。 使用letconst关键字分别可以声明具有块范围的变量和常量。

这意味着,例如,在循环中, if块内或由花括号限制的常规代码块内使用let关键字声明的变量将不会超出该块。 用var声明的变量不保存在此类块中,而是在声明它们的级别的函数中可用。

const关键字的工作方式与let一样,但是使用它,可以声明不可变的常量。

在现代JS代码中,很少使用var关键字。 它让位于letconst关键字。 同时,这似乎很不寻常,但是const关键字在今天已被广泛使用,这表明在现代编程中实体豁免的思想很流行。

班级


事实证明,JavaScript是使用原型继承模型的唯一极为广泛的语言。 在这种环境下,程序员从实现基于类的继承机制的语言切换到JS感到不舒服。 ES2015标准引入了JavaScript中的类支持。 这本质上是使用原型围绕JS内部机制的“语法糖”。 但是,这会影响JS应用程序的精确编写方式。

JavaScript继承机制现在看起来像其他面向对象语言中的类似机制。

 class Person { constructor(name) {   this.name = name } hello() {   return 'Hello, I am ' + this.name + '.' } } class Actor extends Person { hello() {   return super.hello() + ' I am an actor.' } } var tomCruise = new Actor('Tom Cruise') console.log(tomCruise.hello()) 

该程序向控制台显示文本“ Hello, I am Tom Cruise. I am an actorHello, I am Tom Cruise. I am an actor Hello, I am Tom Cruise. I am an actor
在JS类中,无法声明实例变量;必须在构造函数中对其进行初始化。

类构造函数


类有一个特殊的constructor方法,当使用new关键字创建类的实例时会调用该方法。

super关键字超级


super关键字使您可以从后代类访问父类。

▍吸气和吸气


属性的getter可以如下设置。

 class Person { get fullName() {   return `${this.firstName} ${this.lastName}` } } 

设置器的说明如下。

 class Person { set age(years) {   this.theAge = years } } 

它们与getter和setter一起使用,就好像它们不是函数而是对象的普通属性一样。

模组


在ES2015标准之前,有几种使用模块的竞争方法。 特别是,我们正在谈论RequireJS和CommonJS技术。 这种情况导致JS开发人员社区出现了分歧。

如今,由于ES2015中模块的标准化,这种情况正在逐渐正常化。

▍导入模块


使用形式import...from...的结构import...from... 这里有一些例子。

 import * as something from 'mymodule' import React from 'react' import { React, Component } from 'react' import React as MyLibrary from 'react' 

▍导出模块


该模块的内部机制与外界隔离,但您可以从该模块导出它可以提供其他模块的所有内容。 这是使用export关键字完成的。

 export var foo = 2 export function bar() { /* ... */ } 

▍模板文字


模板文字是在JavaScript中描述字符串的新方法。 这是它的外观。

 const aString = `A string` 

此外,使用模板文字的语法可以将表达式嵌入字符串中并进行插值。 这是使用${a_variable}格式的构造完成的。 这是其用法的一个简单示例:

 const v = 'test' const str = `something ${v}` //something test 

这是一个更复杂的示例,说明了评估任何表达式并将其结果替换为字符串的能力。

 const str = `something ${1 + 2 + 3}` const str2 = `something ${foo() ? 'x' : 'y' }` 

由于使用了模板文字,声明多行字符串变得更加容易。

 const str3 = `Hey this string is awesome!` 

将其与使用ES2015之前的语言中可用功能描述多行字符串时需要做的比较。

 var str = 'One\n' + 'Two\n' + 'Three' 

默认功能参数


现在,函数支持默认情况下使用的参数-如果在调用函数时未将相应的参数传递给它们,则这些函数将被支持。

 const foo = function(index = 0, testing = true) { /* ... */ } foo() 

点差运算符


扩展运算符(扩展运算符)使您可以“扩展”数组,对象或字符串。 该运算符看起来像三个点( ... )。 首先,考虑一个数组示例。

 const a = [1, 2, 3] 

这是基于此数组创建新数组的方法。

 const b = [...a, 4, 5, 6] 

这是创建数组副本的方法。

 const c = [...a] 

该运算符还可以处理对象。 例如,这是使用它来克隆对象的方法。

 const newObj = { ...oldObj } 

将扩展运算符应用于字符串,可以将其转换为数组,该数组的每个元素都包含一个来自此字符串的字符。

 const hey = 'hey' const arrayized = [...hey] // ['h', 'e', 'y'] 

除了其应用程序的上述变体之外,此运算符在调用需要正常参数列表的函数并将这些参数传递给它们的数组时方便使用。

 const f = (foo, bar) => {} const a = [1, 2] f(...a) 

以前,这是使用f.apply(null, a)形式的构造完成的,但是这样的代码更难编写,并且可读性更差。

破坏性分配


例如,解构分配技术允许获取一个对象,从该对象中提取一些值,然后将其放入命名的变量或常量中。

 const person = { firstName: 'Tom', lastName: 'Cruise', actor: true, age: 54, } const {firstName: name, age} = person 

在这里, firstNameage属性是从对象中检索的。 将age属性写入以相同名称声明的常量,并且在提取之后, firstName属性属于常量name

破坏性分配也适用于处理数组。

 const a = [1,2,3,4,5] const [first, second, , , fifth] = a 

firstsecondfifth常数分别获取数组的第一,第二和第五个元素。

增强对象文字


ES2015极大地扩展了使用对象文字描述对象的能力。

▍简化对象中变量的包含


以前,为了将变量分配给对象的属性,必须使用以下构造。

 const something = 'y' const x = { something: something } 

现在可以像这样完成同一件事。

 const something = 'y' const x = { something } 

▍原型


现在可以使用以下结构设置对象的原型。

 const anObject = { y: 'y' } const x = { __proto__: anObject } 

super关键字超级


使用super关键字,对象可以访问原型对象。 例如,要调用与这些对象本身的方法具有相同名称的方法。

 const anObject = { y: 'y', test: () => 'zoo' } const x = { __proto__: anObject, test() {   return super.test() + 'x' } } x.test() //zoox 

property计算出的属性名称


计算的属性名称是在对象创建阶段形成的。

 const x = { ['a' + '_' + 'b']: 'z' } x.a_b //z 

对于...的循环


2009年,在ES5标准中,出现了forEach()循环。 这是一种有用的设计,其缺点是这样的循环非常不方便中断。 在需要在正常完成循环之前中断循环执行的情况下,经典的for循环更为合适。

ES2015出现了for...of循环,一方面,其简洁的语法和forEach便利性使其与众不同,另一方面,它支持早期退出循环的可能性。

这里有两个for...of循环示例。

 //    for (const v of ['a', 'b', 'c']) { console.log(v); } //           entries() for (const [i, v] of ['a', 'b', 'c'].entries()) { console.log(i, v); } 

映射并设置数据结构


ES2015引入了MapSet数据结构(以及其“弱”版本WeakMapWeakSet ,它们的使用提高了“垃圾收集器”的性能-负责管理JS引擎中的内存的机制)。 这些是非常流行的数据结构,在正式实施之前,必须使用可用的语言工具来模仿它们。

总结


今天,我们回顾了ES2015标准的功能,这些功能极大地影响了该语言的当前状态。 我们的下一个主题将是ES2016,ES2017和ES2018标准的功能。

亲爱的读者们! 您发现ES6标准的哪些创新最有用?

Source: https://habr.com/ru/post/zh-CN431074/


All Articles