I wrote this article to help you move from pre-ES6 knowledge of JavaScript and get you quickly up to speed with the most recent advancements of the language.

我写这篇文章是为了帮助您摆脱ES6之前JavaScript知识,并Swift掌握该语言的最新进展。

JavaScript today is in the privileged position to be the only language that can run natively in the browser, and is highly integrated and optimized for that.

如今,JavaScript处于特权地位,是唯一可以在浏览器中本地运行的语言,并且对此进行了高度集成和优化。

The future of JavaScript is going to be brilliant. Keeping up with the changes shouldn’t be harder than it already is, and my goal here is to give you a quick yet comprehensive overview of the new stuff available to us.

JavaScript的未来将是辉煌的。 跟上变化的难度不应该比现在更难,我在这里的目标是为您提供对我们可用的新内容的快速而全面的概述。

Click here to get a PDF / ePub / Mobi version of this post to read offline

点击此处获取该帖子的PDF / ePub / Mobi版本以离线阅读

ECMAScript简介 (Introduction to ECMAScript)

Whenever you read about JavaScript you’ll inevitably see one of these terms: ES3, ES5, ES6, ES7, ES8, ES2015, ES2016, ES2017, ECMAScript 2017, ECMAScript 2016, ECMAScript 2015… what do they mean?

每当您阅读有关JavaScript的内容时,都会不可避免地看到以下术语之一:ES3,ES5,ES6,ES7,ES8,ES2015,ES2016,ES2017,ECMAScript 2017,ECMAScript 2016,ECMAScript 2015…是什么意思?

They are all referring to a standard, called ECMAScript.

它们都是指称为ECMAScript的标准

ECMAScript is the standard upon which JavaScript is based, and it’s often abbreviated to ES.

ECMAScript是JavaScript所基于的标准 ,并且通常缩写为ES

Beside JavaScript, other languages implement(ed) ECMAScript, including:

除JavaScript外,其他语言也实现ECMAScript,包括:

  • ActionScript (the Flash scripting language), which is losing popularity since Flash will be officially discontinued in 2020

    由于Flash将于2020年正式停产, ActionScript (Flash脚本语言)正在逐渐消失

  • JScript (the Microsoft scripting dialect), since at the time JavaScript was supported only by Netscape and the browser wars were at their peak, Microsoft had to build its own version for Internet Explorer

    JScript (Microsoft脚本方言),因为当时只有Netscape支持JavaScript,并且浏览器之战已达到顶峰,所以Microsoft必须为Internet Explorer构建自己的版本

but of course JavaScript is the most popular and widely used implementation of ES.

但是,当然,JavaScript是ES中最流行和使用广泛的实现。

Why this weird name? Ecma International is a Swiss standards association who is in charge of defining international standards.

为什么这么奇怪的名字? Ecma International是瑞士标准协会,负责定义国际标准。

When JavaScript was created, it was presented by Netscape and Sun Microsystems to Ecma and they gave it the name ECMA-262 alias ECMAScript.

创建JavaScript时,Netscape和Sun Microsystems将其提供给Ecma,他们给它起了ECMA-262别名ECMAScript的名称。

This press release by Netscape and Sun Microsystems (the maker of Java) might help figure out the name choice, which might include legal and branding issues by Microsoft which was in the committee, according to Wikipedia.

Wikipedia称 ,Netscape和Sun Microsystems (Java的制造商)的本新闻稿可能有助于弄清名称的选择,其中可能包括委员会中的Microsoft的法律和品牌问题。

After IE9, Microsoft stopped branding its ES support in browsers as JScript and started calling it JavaScript (at least, I could not find references to it any more).

IE9之后,Microsoft停止在浏览器中将其对ES支持的品牌标识为JScript,并开始将其称为JavaScript(至少,我再也找不到它的引用了)。

So as of 201x, the only popular language supporting the ECMAScript spec is JavaScript.

因此,从201x开始,支持ECMAScript规范的唯一流行语言是JavaScript。

当前ECMAScript版本 (Current ECMAScript version)

The current ECMAScript version is ES2018.

当前的ECMAScript版本是ES2018

It was released in June 2018.

它于2018年6月发布。

什么是TC39 (What is TC39)

TC39 is the committee that evolves JavaScript.

TC39是开发JavaScript的委员会。

The members of TC39 are companies involved in JavaScript and browser vendors, including Mozilla, Google, Facebook, Apple, Microsoft, Intel, PayPal, SalesForce and others.

TC39的成员是参与JavaScript和浏览器供应商的公司,包括Mozilla,Google,Facebook,Apple,Microsoft,Intel,PayPal,SalesForce等。

Every standard version proposal must go through various stages, which are explained here.

每个标准版本建议都必须经历各个阶段,在此进行解释 。

ES版本 (ES Versions)

I found it puzzling why sometimes an ES version is referenced by edition number and sometimes by year, and I am confused by the year by chance being -1 on the number, which adds to the general confusion around JS/ES ?

我感到困惑,为什么有时会用版本号有时又用年份来引用ES版本,而我对年份却感到困惑,因为偶然的数字是-1,这使人们对JS / ES感到困惑。

Before ES2015, ECMAScript specifications were commonly called by their edition. So ES5 is the official name for the ECMAScript specification update published in 2009.

在ES2015之前,ECMAScript规范通常由其版本调用。 因此,ES5是2009年发布的ECMAScript规范更新的正式名称。

Why does this happen? During the process that led to ES2015, the name was changed from ES6 to ES2015, but since this was done late, people still referenced it as ES6, and the community has not left the edition naming behind — the world is still calling ES releases by edition number.

为什么会这样? 在导致ES2015的过程中,名称从ES6更改为ES2015,但由于此操作进行得很晚,因此人们仍将其称为ES6,并且社区也没有留下版本名称的名称- 世界各地仍在通过以下方式调用ES版本:版本号

This table should clear things up a bit:

该表应将其清除:

Let’s dive into the specific features added to JavaScript since ES5. Let’s start with the ES2015 features.

让我们深入探讨自ES5以来添加到JavaScript的特定功能。 让我们从ES2015功能开始。

let和const (let and const)

Until ES2015, var was the only construct available for defining variables.

在ES2015之前, var是唯一可用于定义变量的构造。

var a = 0

If you forget to add var you will be assigning a value to an undeclared variable, and the results might vary.

如果您忘记添加var ,则将为一个未声明的变量分配一个值,结果可能会有所不同。

In modern environments, with strict mode enabled, you will get an error. In older environments (or with strict mode disabled) this will initialize the variable and assign it to the global object.

在现代环境中,启用严格模式后,您将得到一个错误。 在较旧的环境中(或禁用了严格模式),这将初始化变量并将其分配给全局对象。

If you don’t initialize the variable when you declare it, it will have the undefined value until you assign a value to it.

如果在声明变量时未对其进行初始化,则该变量将具有undefined值,直到您为其分配值为止。

var a //typeof a === 'undefined'

You can redeclare the variable many times, overriding it:

您可以多次声明变量,并将其覆盖:

var a = 1
var a = 2

You can also declare multiple variables at once in the same statement:

您还可以在同一条语句中一次声明多个变量:

var a = 1, b = 2

The scope is the portion of code where the variable is visible.

作用域是代码中可见变量的部分。

A variable initialized with var outside of any function is assigned to the global object, has a global scope and is visible everywhere. A variable initialized with var inside a function is assigned to that function, it's local and is visible only inside it, just like a function parameter.

在任何函数外部用var初始化的变量都分配给全局对象,具有全局作用域,并且随处可见。 将在函数内部使用var初始化的变量分配给该函数,该变量是局部变量,仅在函数内部可见,就像函数参数一样。

Any variable defined in a function with the same name as a global variable takes precedence over the global variable, shadowing it.

与全局变量同名的函数中定义的任何变量都优先于全局变量,并对其进行阴影处理。

It’s important to understand that a block (identified by a pair of curly braces) does not define a new scope. A new scope is only created when a function is created, because var does not have block scope, but function scope.

重要的是要理解一个块(由一对花括号标识)不会定义新的作用域。 仅当创建函数时才创建新作用域,因为var没有块作用域,而是函数作用域。

Inside a function, any variable defined in it is visible throughout all the function code, even if the variable is declared at the end of the function it can still be referenced in the beginning, because JavaScript before executing the code actually moves all variables on top (something that is called hoisting). To avoid confusion, always declare variables at the beginning of a function.

在函数内部,定义在其中的任何变量在整个函数代码中都是可见的,即使在函数的末尾声明了该变量,仍然可以在开始时对其进行引用,因为执行代码之前JavaScript实际上将所有变量移到了顶部 (称为吊装 )。 为避免混淆,请始终在函数的开头声明变量。

使用let (Using let)

let is a new feature introduced in ES2015 and it's essentially a block scoped version of var. Its scope is limited to the block, statement or expression where it's defined, and all the contained inner blocks.

let是ES2015中引入的新功能,本质上是var的块范围版本。 它的范围仅限于定义它的块,语句或表达式,以及所有包含的内部块。

Modern JavaScript developers might choose to only use let and completely discard the use of var.

现代JavaScript开发人员可能会选择只使用let而完全放弃使用var

If let seems an obscure term, just read let color = 'red' as let the color be red and it all makes much more sense

如果let看起来晦涩难懂,请读let color = 'red'因为让颜色为红色,这一切都更有意义

Defining let outside of any function - contrary to var - does not create a global variable.

var相反,在任何函数之外定义let不会创建全局变量。

使用const (Using const)

Variables declared with var or let can be changed later on in the program, and reassigned. Once a const is initialized, its value can never be changed again, and it can't be reassigned to a different value.

varlet声明的变量可以稍后在程序中进行更改,然后重新分配。 const初始化后,其值将永远无法再更改,并且无法将其重新分配给其他值。

const a = 'test'

We can’t assign a different literal to the a const. We can however mutate a if it's an object that provides methods that mutate its contents.

我们不能a const分配其他文字。 然而,我们可以变异a ,如果它是提供了变异的内容方法的对象。

const does not provide immutability, just makes sure that the reference can't be changed.

const不提供不变性,只是确保引用不能更改。

const has block scope, same as let.

const具有块范围,与let相同。

Modern JavaScript developers might choose to always use const for variables that don't need to be reassigned later in the program, because we should always use the simplest construct available to avoid making errors down the road.

现代JavaScript开发人员可能会选择对所有不需要在程序稍后重新分配的变量始终使用const ,因为我们应该始终使用可用的最简单的结构,以避免在以后出错。

箭头功能 (Arrow Functions)

Arrow functions, since their introduction, changed forever how JavaScript code looks (and works).

自从引入箭头功能以来,永远改变了JavaScript代码的外观(和工作方式)。

In my opinion this change was so welcome that you now rarely see the usage of the function keyword in modern codebases. Although that has still its usage.

在我看来,这种更改非常受欢迎,以至于您现在几乎看不到在现代代码库中使用function关键字的情况。 尽管那仍然有它的用法。

Visually, it’s a simple and welcome change, which allows you to write functions with a shorter syntax, from:

从视觉上看,这是一个简单而值得欢迎的更改,它使您可以使用较短的语法编写函数,这些函数来自:

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

to

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

If the function body contains just a single statement, you can omit the brackets and write all on a single line:

如果函数主体仅包含一条语句,则可以省略方括号并将所有内容写在一行上:

const myFunction = () => doSomething()

Parameters are passed in the parentheses:

参数在括号中传递:

const myFunction = (param1, param2) => doSomething(param1, param2)

If you have one (and just one) parameter, you could omit the parentheses completely:

如果有一个(只有一个)参数,则可以完全省略括号:

const myFunction = param => doSomething(param)

Thanks to this short syntax, arrow functions encourage the use of small functions.

由于这种简短的语法,箭头函数鼓励使用小函数

隐式回报 (Implicit return)

Arrow functions allow you to have an implicit return: values are returned without having to use the return keyword.

箭头函数使您可以隐式返回:无需使用return关键字即可返回值。

It works when there is a one-line statement in the function body:

当函数体中有单行语句时,它可以工作:

const myFunction = () => 'test'myFunction() //'test'

Another example, when returning an object, remember to wrap the curly brackets in parentheses to avoid it being considered the wrapping function body brackets:

另一个示例,在返回对象时,请记住将花括号括在括号中,以避免将其视为包裹函数的主体括号:

const myFunction = () => ({ value: 'test' })myFunction() //{value: 'test'}

如何this作品箭头功能 (How this works in arrow functions)

this is a concept that can be complicated to grasp, as it varies a lot depending on the context and also varies depending on the mode of JavaScript (strict mode or not).

this是一个很难理解的概念,因为它随上下文而变化很大,并且还取决于JavaScript的模式(是否为严格模式 )。

It’s important to clarify this concept because arrow functions behave very differently compared to regular functions.

弄清这个概念很重要,因为箭头函数的行为与常规函数非常不同。

When defined as a method of an object, in a regular function this refers to the object, so you can do:

当定义为对象的方法时,在常规函数中, this引用该对象,因此您可以执行以下操作:

const car = {model: 'Fiesta',manufacturer: 'Ford',fullName: function() {return `${this.manufacturer} ${this.model}`}
}

calling car.fullName() will return "Ford Fiesta".

调用car.fullName()将返回"Ford Fiesta"

The this scope with arrow functions is inherited from the execution context. An arrow function does not bind this at all, so its value will be looked up in the call stack, so in this code car.fullName() will not work, and will return the string "undefined undefined":

this箭头的功能范围从执行上下文继承 。 箭头函数根本不会绑定this函数,因此将在调用堆栈中查找其值,因此在此代码中car.fullName()将不起作用,并将返回字符串"undefined undefined"

const car = {model: 'Fiesta',manufacturer: 'Ford',fullName: () => {return `${this.manufacturer} ${this.model}`}
}

Due to this, arrow functions are not suited as object methods.

因此,箭头功能不适合作为对象方法。

Arrow functions cannot be used as constructors either, when instantiating an object will raise a TypeError.

箭头函数也不能用作构造函数,在实例化对象时会引发TypeError

This is where regular functions should be used instead, when dynamic context is not needed.

当不需要动态上下文时 ,应在此处使用常规函数代替。

This is also a problem when handling events. DOM Event listeners set this to be the target element, and if you rely on this in an event handler, a regular function is necessary:

在处理事件时,这也是一个问题。 DOM事件监听器设置this是目标元素,如果依靠this在事件处理程序,一个普通的功能是必要的:

const link = document.querySelector('#link')
link.addEventListener('click', () => {// this === window
})const link = document.querySelector('#link')
link.addEventListener('click', function() {// this === link
})

班级 (Classes)

JavaScript has quite an uncommon way to implement inheritance: prototypical inheritance. Prototypal inheritance, while in my opinion great, is unlike most other popular programming language’s implementation of inheritance, which is class-based.

JavaScript有一种非常不常见的实现继承的方法:原型继承。 在我看来, 原型继承虽然很棒,但与大多数其他流行的编程语言基于类的继承不同。

People coming from Java or Python or other languages had a hard time understanding the intricacies of prototypal inheritance, so the ECMAScript committee decided to sprinkle syntactic sugar on top of prototypical inheritance so that it resembles how class-based inheritance works in other popular implementations.

来自Java,Python或其他语言的人们很难理解原型继承的复杂性,因此ECMAScript委员会决定在原型继承的基础上撒上语法糖,以使其类似于基于类的继承在其他流行实现中的工作方式。

This is important: JavaScript under the hood is still the same, and you can access an object prototype in the usual way.

这很重要:底层JavaScript仍然相同,并且您可以以通常的方式访问对象原型。

类定义 (A class definition)

This is how a class looks.

这是一个类的外观。

class Person {constructor(name) {this.name = name}hello() {return 'Hello, I am ' + this.name + '.'}
}

A class has an identifier, which we can use to create new objects using new ClassIdentifier().

一个类具有一个标识符,我们可以使用它使用new ClassIdentifier()创建新对象。

When the object is initialized, the constructor method is called, with any parameters passed.

初始化对象时,将调用传递任何参数的constructor方法。

A class also has as many methods as it needs. In this case hello is a method and can be called on all objects derived from this class:

一个类还具有所需的许多方法。 在这种情况下, hello是一种方法,可以在派生自此类的所有对象上调用:

const flavio = new Person('Flavio')
flavio.hello()

类继承 (Class inheritance)

A class can extend another class, and objects initialized using that class inherit all the methods of both classes.

一个类可以扩展另一个类,并且使用该类初始化的对象将继承这两个类的所有方法。

If the inherited class has a method with the same name as one of the classes higher in the hierarchy, the closest method takes precedence:

如果继承的类具有与层次结构中较高级别的类之一名称相同的方法,则最接近的方法优先:

class Programmer extends Person {hello() {return super.hello() + ' I am a programmer.'}
}const flavio = new Programmer('Flavio')
flavio.hello()

(the above program prints “Hello, I am Flavio. I am a programmer.”)

(上面的程序打印“ 您好,我是Flavio。我是程序员。 ”)

Classes do not have explicit class variable declarations, but you must initialize any variable in the constructor.

类没有显式的类变量声明,但是必须在构造函数中初始化任何变量。

Inside a class, you can reference the parent class calling super().

在类内部,可以引用父类调用super()

静态方法 (Static methods)

Normally methods are defined on the instance, not on the class.

通常,方法是在实例上定义的,而不是在类上定义的。

Static methods are executed on the class instead:

静态方法改为在类上执行:

class Person {static genericHello() {return 'Hello'}
}Person.genericHello() //Hello

私人方法 (Private methods)

JavaScript does not have a built-in way to define private or protected methods.

JavaScript没有内置的方法来定义私有或受保护的方法。

There are workarounds, but I won’t describe them here.

有解决方法,但在此不再赘述。

吸气剂和二传手 (Getters and setters)

You can add methods prefixed with get or set to create a getter and setter, which are two different pieces of code that are executed based on what you are doing: accessing the variable, or modifying its value.

您可以添加以getset为前缀的方法来创建getter和setter,这是基于您正在执行的操作的两个不同的代码段:访问变量或修改其值。

class Person {constructor(name) {this._name = name}set name(value) {this._name = value}get name() {return this._name}
}

If you only have a getter, the property cannot be set, and any attempt at doing so will be ignored:

如果您只有吸气剂,则无法设置该属性,并且这样做的任何尝试都将被忽略:

class Person {constructor(name) {this._name = name}get name() {return this._name}
}

If you only have a setter, you can change the value but not access it from the outside:

如果只有二传手,则可以更改值,但不能从外部访问它:

class Person {constructor(name) {this._name = name}set name(value) {this._name = value}
}

默认参数 (Default parameters)

This is a doSomething function which accepts param1.

这是一个接受参数param1doSomething函数。

const doSomething = (param1) => {}

We can add a default value for param1 if the function is invoked without specifying a parameter:

如果在不指定参数的情况下调用函数,我们可以为param1添加默认值:

const doSomething = (param1 = 'test') => {}

This works for more parameters as well, of course:

当然,这也适用于更多参数:

const doSomething = (param1 = 'test', param2 = 'test2') => {}

What if you have an unique object with parameters values in it?

如果您有一个带有参数值的唯一对象怎么办?

Once upon a time, if we had to pass an object of options to a function, in order to have default values of those options if one of them was not defined, you had to add a little bit of code inside the function:

曾几何时,如果我们必须将选项对象传递给函数,如果未定义其中一个选项,则要具有这些选项的默认值,则必须在函数内部添加一些代码:

const colorize = (options) => {if (!options) {options = {}}const color = ('color' in options) ? options.color : 'yellow'...
}

With destructuring you can provide default values, which simplifies the code a lot:

通过解构,您可以提供默认值,从而大大简化了代码:

const colorize = ({ color = 'yellow' }) => {...
}

If no object is passed when calling our colorize function, similarly we can assign an empty object by default:

如果在调用我们的colorize函数时没有传递任何对象,则类似地,我们可以默认分配一个空对象:

const spin = ({ color = 'yellow' } = {}) => {...
}

模板文字 (Template Literals)

Template Literals allow you to work with strings in a novel way compared to ES5 and below.

与ES5及以下版本相比,模板文字使您可以以新颖的方式使用字符串。

The syntax at a first glance is very simple, just use backticks instead of single or double quotes:

乍一看语法非常简单,只需使用反引号代替单引号或双引号即可:

const a_string = `something`

They are unique because they provide a lot of features that normal strings built with quotes do not, in particular:

它们之所以独特是因为它们提供了很多用引号构建的普通字符串所没有的功能,特别是:

  • they offer a great syntax to define multiline strings它们提供了定义多行字符串的绝佳语法
  • they provide an easy way to interpolate variables and expressions in strings它们提供了一种简单的方法来对字符串中的变量和表达式进行插值
  • they allow you to create DSLs with template tags (DSL means domain specific language, and it’s for example used in React by Styled Components, to define CSS for a component)它们允许您使用模板标签创建DSL(DSL表示域特定的语言,例如,在React by Styled Components中使用,以为组件定义CSS)

Let’s dive into each of these in detail.

让我们详细研究每个。

多行字符串 (Multiline strings)

Pre-ES6, to create a string spanning over two lines you had to use the \ character at the end of a line:

在ES6之前的版本中,要创建跨越两行的字符串,您必须在行末使用\字符:

const string ='first part \
second part'

This allows to create a string on 2 lines, but it’s rendered on just one line:

这允许在两行上创建一个字符串,但是仅在一行上呈现:

first part second part

first part second part

To render the string on multiple lines as well, you explicitly need to add \n at the end of each line, like this:

要同时在多行上呈现字符串,您需要明确地在每行的末尾添加\n ,如下所示:

const string ='first line\n \
second line'

or

要么

const string = 'first line\n' + 'second line'

Template literals make multiline strings much simpler.

模板文字使多行字符串更简单。

Once a template literal is opened with the backtick, you just press enter to create a new line, with no special characters, and it’s rendered as-is:

使用反引号打开模板文字后,只需按Enter键即可创建新行(不包含任何特殊字符),并按原样呈现:

const string = `Hey
thisstring
is awesome!`

Keep in mind that space is meaningful, so doing this:

请记住,空间是有意义的,因此请执行以下操作:

const string = `FirstSecond`

is going to create a string like this:

将创建这样的字符串:

FirstSecond

an easy way to fix this problem is by having an empty first line, and appending the trim() method right after the closing backtick, which will eliminate any space before the first character:

解决此问题的一种简单方法是,在第一行为空,并在结束反引号之后附加trim()方法,这将消除第一个字符之前的任何空格:

const string = `
First
Second`.trim()

插补 (Interpolation)

Template literals provide an easy way to interpolate variables and expressions into strings.

模板文字提供了一种将变量和表达式内插到字符串中的简便方法。

You do so by using the ${...} syntax:

您可以使用${...}语法来实现:

const var = 'test'
const string = `something ${var}` //something test

inside the ${} you can add anything, even expressions:

${}您可以添加任何内容,甚至是表达式:

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

模板标签 (Template tags)

Tagged templates is one feature that might sound less useful at first for you, but it’s actually used by lots of popular libraries around, like Styled Components or Apollo, the GraphQL client/server lib, so it’s essential to understand how it works.

标记模板是一个功能,乍一看对您来说似乎没什么用,但是实际上它被许多流行的库使用,例如Styled Components或GraphQL客户/服务器库Apollo,因此了解它的工作原理非常重要。

In Styled Components template tags are used to define CSS strings:

在“样式化组件”中,模板标记用于定义CSS字符串:

const Button = styled.button`font-size: 1.5em;background-color: black;color: white;
`

In Apollo template tags are used to define a GraphQL query schema:

在Apollo中,模板标记用于定义GraphQL查询架构:

const query = gql`query {...}
`

The styled.button and gql template tags highlighted in those examples are just functions:

这些示例中突出显示的styled.buttongql模板标签只是函数

function gql(literals, ...expressions) {}

this function returns a string, which can be the result of any kind of computation.

此函数返回一个字符串,该字符串可以是任何类型的计算的结果。

literals is an array containing the template literal content tokenized by the expressions interpolations.

literals是一个数组,其中包含由表达式插值标记的模板文字内容。

expressions contains all the interpolations.

expressions包含所有插值。

If we take an example above:

如果我们以上述示例为例:

const string = `something ${1 + 2 + 3}`

literals is an array with two items. The first is something, the string until the first interpolation, and the second is an empty string, the space between the end of the first interpolation (we only have one) and the end of the string.

literals是具有两个项目的数组。 第一个是something ,直到第一个插值为止的字符串,第二个是空字符串,即第一个插值的结尾(我们只有一个)和字符串的结尾之间的空格。

expressions in this case is an array with a single item, 6.

在这种情况下, expressions是具有单个项目6的数组。

A more complex example is:

一个更复杂的示例是:

const string = `something
another ${'x'}
new line ${1 + 2 + 3}
test`

in this case literals is an array where the first item is:

在这种情况下, literals是一个数组,其中第一项是:

;`something
another `

the second is:

第二个是:

;`new line `

and the third is:

第三是:

;`
new line `

expressions in this case is an array with two items, x and 6.

在这种情况下, expressions是一个具有两项x6的数组。

The function that is passed those values can do anything with them, and this is the power of this kind feature.

传递这些值的函数可以对它们执行任何操作,而这正是此类功能的强大功能。

The most simple example is replicating what the string interpolation does, by joining literals and expressions:

最简单的示例是通过连接literalsexpressions来复制字符串插值的expressions

const interpolated = interpolate`I paid ${10}€`

and this is how interpolate works:

这是interpolate工作方式:

function interpolate(literals, ...expressions) {let string = ``for (const [i, val] of expressions) {string += literals[i] + val}string += literals[literals.length - 1]return string
}

销毁工作 (Destructuring assignments)

Given an object, you can extract just some values and put them into named variables:

给定一个对象,您可以仅提取一些值并将其放入命名变量中:

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

name and age contain the desired values.

nameage包含所需的值。

The syntax also works on arrays:

该语法也适用于数组:

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

This statement creates 3 new variables by getting the items with index 0, 1, 4 from the array a:

该语句通过从数组a获取索引为0、1、4的项来创建3个新变量:

增强的对象文字 (Enhanced Object Literals)

const [first, second, , , fifth] = a

In ES2015 Object Literals gained superpowers.

在ES2015中,Object Literals获得了超能力。

包含变量的语法更简单 (Simpler syntax to include variables)

Instead of doing

而不是做

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

you can do

你可以做

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

原型 (Prototype)

A prototype can be specified with

原型可以用

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

超() (super())

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

动态特性 (Dynamic properties)

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

循环循环 (For-of loop)

ES5 back in 2009 introduced forEach() loops. While nice, they offered no way to break, like for loops always did.

早在2009年,ES5就引入了forEach()循环。 虽然不错,但它们没有提供中断的方法,就像for循环总是一样。

ES2015 introduced the for-of loop, which combines the conciseness of forEach with the ability to break:

ES2015引入了for-of 循环 ,该循环结合了forEach的简洁性和打破能力:

//iterate over the value
for (const v of ['a', 'b', 'c']) {console.log(v);
}//get the index as well, using `entries()`
for (const [i, v] of ['a', 'b', 'c'].entries()) {console.log(index) //indexconsole.log(value) //value
}

Notice the use of const. This loop creates a new scope in every iteration, so we can safely use that instead of let.

注意const的使用。 这个循环在每次迭代中都会创建一个新的作用域,因此我们可以放心地使用它代替let

The difference with for...in is:

for...in的区别是:

  • for...of iterates over the property values

    for...of 迭代属性值

  • for...in iterates the property names

    for...in 迭代属性名称

承诺 (Promises)

A promise is commonly defined as a proxy for a value that will eventually become available.

通常将promise定义为最终将变为可用值的代理

Promises are one way to deal with asynchronous code, without writing too many callbacks in your code.

承诺是处理异步代码的一种方法,而无需在代码中编写过多的回调。

Async functions use the promises API as their building block, so understanding them is fundamental even if in newer code you’ll likely use async functions instead of promises.

异步函数将promise API用作其构建块,因此即使在较新的代码中您可能会使用异步函数代替promise,对它们的理解也是基础。

简而言之,诺言如何运作 (How promises work, in brief)

Once a promise has been called, it will start in pending state. This means that the caller function continues the execution, while it waits for the promise to do its own processing, and give the caller function some feedback.

承诺被调用后,它将以待处理状态开始。 这意味着调用方函数继续执行,同时等待promise进行自己的处理,并向调用方函数提供一些反馈。

At this point, the caller function waits for it to either return the promise in a resolved state, or in a rejected state, but as you know JavaScript is asynchronous, so the function continues its execution while the promise does it work.

此时,调用者函数等待它以已解决状态或被拒绝状态返回promise,但是您知道JavaScript是异步的,因此该函数在promise起作用的同时继续执行

哪个JS API使用承诺? (Which JS API use promises?)

In addition to your own code and library code, promises are used by standard modern Web APIs such as:

除了您自己的代码和库代码之外,标准的现代Web API还使用了promise,例如:

  • the Battery API电池API
  • the Fetch API

    提取API

  • Service Workers

    服务人员

It’s unlikely that in modern JavaScript you’ll find yourself not using promises, so let’s start diving right into them.

在现代JavaScript中,您不太可能会发现自己没有使用Promise,因此让我们开始深入研究它们。

创造承诺 (Creating a promise)

The Promise API exposes a Promise constructor, which you initialize using new Promise():

Promise API公开了一个Promise构造函数,您可以使用new Promise()初始化:

let done = trueconst isItDoneYet = new Promise((resolve, reject) => {if (done) {const workDone = 'Here is the thing I built'resolve(workDone)} else {const why = 'Still working on something else'reject(why)}
})

As you can see the promise checks the done global constant, and if that's true, we return a resolved promise, otherwise a rejected promise.

如您所见,promise检查已done全局常量,如果是这样,我们将返回已解决的Promise,否则将返回被拒绝的Promise。

Using resolve and reject we can communicate back a value, in the above case we just return a string, but it could be an object as well.

使用resolvereject我们可以返回一个值,在上述情况下,我们只返回一个字符串,但是它也可以是一个对象。

兑现承诺 (Consuming a promise)

In the last section, we introduced how a promise is created.

在上一节中,我们介绍了如何创建承诺。

Now let’s see how the promise can be consumed or used.

现在,让我们来看看如何承诺可以消耗或使用。

const isItDoneYet = new Promise()
//...const checkIfItsDone = () => {isItDoneYet.then(ok => {console.log(ok)}).catch(err => {console.error(err)})
}

Running checkIfItsDone() will execute the isItDoneYet() promise and will wait for it to resolve, using the then callback, and if there is an error, it will handle it in the catch callback.

运行checkIfItsDone()将执行isItDoneYet() ,并使用then回调等待其解决,如果有错误,它将在catch回调中对其进行处理。

连锁承诺 (Chaining promises)

A promise can be returned to another promise, creating a chain of promises.

一个承诺可以返回到另一个承诺,从而创建一个承诺链。

A great example of chaining promises is given by the Fetch API, a layer on top of the XMLHttpRequest API, which we can use to get a resource and queue a chain of promises to execute when the resource is fetched.

链接承诺的一个很好的例子是Fetch API ,它是XMLHttpRequest API之上的一层,我们可以使用它来获取资源,并在获取资源时排队执行承诺。

The Fetch API is a promise-based mechanism, and calling fetch() is equivalent to defining our own promise using new Promise().

Fetch API是一种基于承诺的机制,调用fetch()等效于使用new Promise()定义我们自己的承诺。

链接承诺的示例 (Example of chaining promises)

const status = response => {if (response.status >= 200 && response.status < 300) {return Promise.resolve(response)}return Promise.reject(new Error(response.statusText))
}const json = response => response.json()fetch('/todos.json').then(status).then(json).then(data => {console.log('Request succeeded with JSON response', data)}).catch(error => {console.log('Request failed', error)})

In this example, we call fetch() to get a list of TODO items from the todos.json file found in the domain root, and we create a chain of promises.

在此示例中,我们调用fetch()从域根目录中的todos.json文件中获取TODO项目列表,并创建一个Promise链。

Running fetch() returns a response, which has many properties, and within those we reference:

运行fetch()返回一个response ,它具有许多属性,在我们引用的属性内:

  • status, a numeric value representing the HTTP status code

    status ,一个表示HTTP状态代码的数值

  • statusText, a status message, which is OK if the request succeeded

    statusText ,状态消息,如果请求成功,则OK

response also has a json() method, which returns a promise that will resolve with the content of the body processed and transformed into JSON.

response也有一个json()方法,该方法返回一个promise,该promise将与处理并转换为JSON的正文内容一起解析。

So given those premises, this is what happens: the first promise in the chain is a function that we defined, called status(), that checks the response status and if it's not a success response (between 200 and 299), it rejects the promise.

因此,考虑到这些前提,就会发生这种情况:链中的第一个promise是我们定义的函数,即status() ,它检查响应状态,如果不是成功响应(介于200和299之间),它将拒绝诺言。

This operation will cause the promise chain to skip all the chained promises listed and will skip directly to the catch() statement at the bottom, logging the Request failed text along with the error message.

此操作将导致promise链跳过列出的所有链接的promise,并将直接跳到底部的catch()语句,并记录Request failed文本和错误消息。

If that succeeds instead, it calls the json() function we defined. Since the previous promise, when successful, returned the response object, we get it as an input to the second promise.

如果成功,它将调用我们定义的json()函数。 由于上一个承诺成功后返回了response对象,因此我们将其作为第二个承诺的输入。

In this case, we return the data JSON processed, so the third promise receives the JSON directly:

在这种情况下,我们返回经过JSON处理的数据,因此第三个promise直接接收JSON:

.then((data) => {console.log('Request succeeded with JSON response', data)
})

and we log it to the console.

然后将其记录到控制台。

处理错误 (Handling errors)

In the above example, in the previous section, we had a catch that was appended to the chain of promises.

在上面的例子中,上一节中,我们有一个catch这是附加承诺的链条。

When anything in the chain of promises fails and raises an error or rejects the promise, the control goes to the nearest catch() statement down the chain.

当promise链中的任何内容失败并且引发错误或拒绝promise时,控件将转到链中最近的catch()语句。

new Promise((resolve, reject) => {throw new Error('Error')
}).catch(err => {console.error(err)
})// ornew Promise((resolve, reject) => {reject('Error')
}).catch(err => {console.error(err)
})

级联错误 (Cascading errors)

If inside the catch() you raise an error, you can append a second catch() to handle it, and so on.

如果在catch()内部引发错误,则可以附加第二个catch()来处理它,依此类推。

new Promise((resolve, reject) => {throw new Error('Error')
}).catch(err => {throw new Error('Error')}).catch(err => {console.error(err)})

编排承诺 (Orchestrating promises)

Promise.all() (Promise.all())

If you need to synchronize different promises, Promise.all() helps you define a list of promises, and execute something when they are all resolved.

如果您需要同步不同的Promise.all()Promise.all()可帮助您定义一个Promise.all()列表,并在它们全部解决后执行一些操作。

Example:

例:

const f1 = fetch('/something.json')
const f2 = fetch('/something2.json')Promise.all([f1, f2]).then(res => {console.log('Array of results', res)}).catch(err => {console.error(err)})

The ES2015 destructuring assignment syntax allows you to also do

ES2015解构分配语法使您还可以

Promise.all([f1, f2]).then(([res1, res2]) => {console.log('Results', res1, res2)
})

You are not limited to using fetch of course, any promise is good to go.

当然,您不仅限于使用fetch任何承诺都是可以的

Promise.race() (Promise.race())

Promise.race() runs as soon as one of the promises you pass to it resolves, and it runs the attached callback just once with the result of the first promise resolved.

Promise.race()在您传递给它的一个诺言解析后立即运行,并且在第一个诺言得到解决的情况下,它仅运行附加的回调一次。

Example:

例:

const promiseOne = new Promise((resolve, reject) => {setTimeout(resolve, 500, 'one')
})
const promiseTwo = new Promise((resolve, reject) => {setTimeout(resolve, 100, 'two')
})Promise.race([promiseOne, promiseTwo]).then(result => {console.log(result) // 'two'
})

模组 (Modules)

ES Modules is the ECMAScript standard for working with modules.

ES模块是用于模块的ECMAScript标准。

While Node.js has been using the CommonJS standard for years, the browser never had a module system, as every major decision such as a module system must be first standardized by ECMAScript and then implemented by the browser.

尽管Node.js多年来一直使用CommonJS标准,但浏览器从未拥有模块系统,因为诸如模块系统之类的每个主要决策都必须首先由ECMAScript标准化,然后由浏览器实现。

This standardization process completed with ES2015 and browsers started implementing this standard trying to keep everything well aligned, working all in the same way, and now ES Modules are supported in Chrome, Safari, Edge and Firefox (since version 60).

该标准化过程已在ES2015中完成,浏览器开始实施此标准,以使所有内容保持一致,并以相同的方式工作,现在Chrome,Safari,Edge和Firefox(版本60开始)均支持ES模块。

Modules are very cool, because they let you encapsulate all sorts of functionality, and expose this functionality to other JavaScript files, as libraries.

模块非常酷,因为它们使您可以封装各种功能,并将该功能作为库公开给其他JavaScript文件。

ES模块语法 (The ES Modules Syntax)

The syntax to import a module is:

导入模块的语法为:

import package from 'module-name'

while CommonJS uses

而CommonJS使用

const package = require('module-name')

A module is a JavaScript file that exports one or more values (objects, functions or variables), using the export keyword. For example, this module exports a function that returns a string uppercase:

模块是一个JavaScript文件,该文件使用export关键字导出一个或多个值(对象,函数或变量)。 例如,此模块导出一个返回大写字符串的函数:

uppercase.js

uppercase.js

export default str => str.toUpperCase()

In this example, the module defines a single, default export, so it can be an anonymous function. Otherwise it would need a name to distinguish it from other exports.

在此示例中,模块定义了一个默认的export ,因此它可以是匿名函数。 否则,将需要一个名称来区别于其他出口。

Now, any other JavaScript module can import the functionality offered by uppercase.js by importing it.

现在, 任何其他JavaScript模块都可以通过导入来导入uppercase.js提供的功能。

An HTML page can add a module by using a <script> tag with the special type="module" attribute:

HTML页面可以通过使用具有ecial type="m odule”属性的<scri pt>标记来添加模块:

<script type="module" src="index.js"></script>

Note: this module import behaves like a defer script load. See efficiently load JavaScript with defer and async

注意:此模块导入的行为类似于defer脚本加载。 通过延迟和异步查看有效加载JavaScript

It’s important to note that any script loaded with type="module" is loaded in strict mode.

重要的是要注意,任何以type="module"加载的脚本都以严格模式加载。

In this example, the uppercase.js module defines a default export, so when we import it, we can assign it a name we prefer:

在此示例中, uppercase.js模块定义了默认的export ,因此,当我们导入它时,我们可以为其指定一个我们更喜欢的名称:

import toUpperCase from './uppercase.js'

and we can use it:

我们可以使用它:

toUpperCase('test') //'TEST'

You can also use an absolute path for the module import, to reference modules defined on another domain:

您还可以使用绝对路径进行模块导入,以引用在另一个域上定义的模块:

import toUpperCase from 'https://flavio-es-modules-example.glitch.me/uppercase.js'

This is also valid import syntax:

这也是有效的导入语法:

import { toUpperCase } from '/uppercase.js'
import { toUpperCase } from '../uppercase.js'

This is not:

这不是:

import { toUpperCase } from 'uppercase.js'
import { toUpperCase } from 'utils/uppercase.js'

It’s either absolute, or has a ./ or / before the name.

它可以是绝对的,也可以在名称前带有.//

其他导入/导出选项 (Other import/export options)

We saw this example above:

我们在上面看到了这个例子:

export default str => str.toUpperCase()

This creates one default export. In a file however you can export more than one thing, by using this syntax:

这将创建一个默认导出。 但是,在文件中,可以使用以下语法导出多个内容:

const a = 1
const b = 2
const c = 3export { a, b, c }

Another module can import all those exports using

另一个模块可以使用

import * from 'module'

You can import just a few of those exports, using the destructuring assignment:

使用解构分配,您可以仅导入其中一些导出:

import { a } from 'module'
import { a, b } from 'module'

You can rename any import, for convenience, using as:

您可以重命名任何进口,为方便起见,使用as

import { a, b as two } from 'module'

You can import the default export, and any non-default export by name, like in this common React import:

您可以导入默认导出,也可以按名称导入任何非默认导出,例如在此常见的React导入中:

import React, { Component } from 'react'

You can see an ES Modules example here: https://glitch.com/edit/#!/flavio-es-modules-example?path=index.html

您可以在此处看到ES模块示例: https : //glitch.com/edit/#!/ flavio-es-modules-example ?path=index.html

CORS (CORS)

Modules are fetched using CORS. This means that if you reference scripts from other domains, they must have a valid CORS header that allows cross-site loading (like Access-Control-Allow-Origin: *)

使用CORS提取模块。 这意味着,如果您引用其他域中的脚本,则它们必须具有有效的CORS标头,以允许跨站点加载(例如Access-Control-Allow-Origin: * )。

不支持模块的浏览器呢? (What about browsers that do not support modules?)

Use a combination of type="module" and nomodule:

使用type="module"nomodule

<script type="module" src="module.js"></script>
<script nomodule src="fallback.js"></script>

包装模块 (Wrapping up modules)

ES Modules are one of the biggest features introduced in modern browsers. They are part of ES6 but the road to implement them has been long.

ES模块是现代浏览器中引入的最大功能之一。 它们是ES6的一部分,但是实现它们的路很长。

We can now use them! But we must also remember that having more than a few modules is going to have a performance hit on our pages, as it’s one more step that the browser must perform at runtime.

我们现在可以使用它们了! 但是我们还必须记住,拥有多个模块将对我们的页面产生性能影响,因为这是浏览器在运行时必须执行的又一步。

Webpack is probably going to still be a huge player even if ES Modules land in the browser, but having such a feature directly built in the language is huge for a unification of how modules work client-side and on Node.js as well.

即使ES模块位于浏览器中,Webpack仍将扮演重要角色,但是直接用该语言构建这样的功能对于统一模块在客户端以及在Node.js上的工作方式来说是巨大的。

新的String方法 (New String methods)

Any string value got some new instance methods:

任何字符串值都有一些新的实例方法:

  • repeat()

    repeat()

  • codePointAt()

    codePointAt()

重复() (repeat())

Repeats the strings for the specified number of times:

将字符串重复指定的次数:

'Ho'.repeat(3) //'HoHoHo'

Returns an empty string if there is no parameter, or the parameter is 0. If the parameter is negative you'll get a RangeError.

如果没有参数,或者参数为0 ,则返回一个空字符串。 如果参数为负,则会出现RangeError。

codePointAt() (codePointAt())

This method can be used to handle Unicode characters that cannot be represented by a single 16-bit Unicode unit, but need 2 instead.

此方法可用于处理无法用单个16位Unicode单元表示但需要2个字符的Unicode字符。

Using charCodeAt() you need to retrieve the first, and the second, and combine them. Using codePointAt() you get the whole character in one call.

使用charCodeAt()您需要检索第一个和第二个,并将它们合并。 使用codePointAt()可以一次调用整个字符。

For example, this Chinese character “

从ES5到ESNext-这是自2015年以来添加到JavaScript的所有功能相关推荐

  1. ES5 to ESNext —  自 2015 以来 JavaScript 新增的所有新特性

    type: FrontEnd title: ES5 to ESNext - here's every feature added to JavaScript since 2015 link: medi ...

  2. 2015年1月微信上线原创声明功能:智能添加原创标识 转载自动注明出处

    微信上线原创声明功能:智能添加原创标识 转载自动注明出处 2015.01.23 08:46:00来源: TechWeb.com.cn 作者:周小白 http://www.techweb.com.cn/ ...

  3. 解决 | VS 2015右键项目添加新项中没有web窗体等选项

    刚装完的VS2015,打开网站之后右键项目添加新项时,没有web窗体,SQL Server数据库等选项,如: 解决方法:工具->扩展和更新: 更新安装ASP.NET 工具(下图两个都装): 更新 ...

  4. 【前端】2015阿里前端实习生在线笔试题

    网上找的题,自己做了做. ... 2015阿里巴巴前端实习生在线笔试题 1. (单项选择)对于下列程序运行结果,符合预期的是 function f1() { console.time('time sp ...

  5. 2015某大型电商集团的前端实习生在线笔试题(无耻的拿来偷看了)

    2015某大型电商集团的前端实习生在线笔试题(嘿嘿猜猜是谁的) 1.(单项选择)对于下列程序运行结果,符合预期的是 function f1() { console.time('time span'); ...

  6. 2015 上半年 JavaScript 使用统计数据

    jQuery,作为近几年 JS 开发环境中常用的 JavaScript 框架,已经传播到 200 万的新域名,有效的提高了 4% 的市场占有率.这非常令人惊讶,因为现在越来越多的开发者转向 Angul ...

  7. 最佳开源大数据工具-2015

    1. Spark 在Apache的大数据项目中,Spark是最火的一个,特别是像IBM这样的重量级贡献者的深入参与,使得Spark的发展和进步速度飞快. 与Spark产生最甜蜜的火花点仍然是在机器学习 ...

  8. 苹果商店App Store审核指南中文版(14-15-2016最新)-附:2015年App Store审核被拒Top10(官网)+被拒的23个理由(中英)

    (2014.9.3更新):新增Apple Pay相关内容 苹果在9月3日对App Store审核指南进行了重大更新,新添加了扩展.HealthKit.HomeKit以及TestFlight相关内容.另 ...

  9. 2015年App Store审核被拒的23个理由

    iOS 应用提交审核要持续一周或者更久,在提交之前,我们一定要进行「自我审查」,避免被拒.ASO100 为大家收集整理了2015年 App Store 审核被拒的23个理由,并且附上官方拒绝理由原文, ...

最新文章

  1. 数据蒋堂 | 从一道招聘考题谈起
  2. python3 信号量和线程池 semaphore ThreadPollExector
  3. 洛谷——P1583 魔法照片
  4. 数据库优化:52 条 SQL 语句性能优化策略,果断收藏!
  5. android 获取monkey日志_Android压力测试:monkey压力测试实战
  6. python程序可以在任何安装了解释器_Python解释器新手安装教程
  7. slot是什么?有什么作用?
  8. 使用Python Seaborn和Pandas进行数据可视化
  9. mysql n叉树_MySQL索引底层:B+树详解
  10. 企业上云计算最大的障碍是什么?
  11. Unity首次运行下载游戏资源
  12. 酷开系统上线共抗疫情版块
  13. 实验2-1-2 温度转换 (5 分)
  14. C 类IP 地址,连接6 个子公司
  15. 程序员版本的八荣八耻,爱了
  16. OSChina 周四乱弹 ——老司机的幼年日常
  17. MUTAN:Multimodal Tucker Fusion For Visual Question Answering
  18. hyper-v虚拟机开启失败导致无网络或进入公司内网后无网络
  19. html设置文本域的,HTML-文本域属性设置
  20. 【一周头条盘点】中国软件网(2018.8.20~2018.8.24)

热门文章

  1. 优美的数列(斐波那契数列)
  2. Tecno(传音)手机在非洲市场占有率高达40%,成功原因是?
  3. linux生成秘钥库,在Linux中,生成强预共享密钥(PSK )的4种方法
  4. linux 开启 键盘的背光灯
  5. c语言分拆素数和,分拆素数和。
  6. es拼音分词 大帅哥_8 种架构设计模式优缺点大曝光 | 原力计划
  7. python批量裁剪图像
  8. excel多窗口分屏并列显示
  9. 在Windows Server 2022系统上安装 Brother MFC-7450打印机驱动
  10. 计算机的维修有两种,两个汽车电脑维修案例 你未必会修