ECMAScript是JavaScript基于的标准,通常缩写为ES。了解关于ECMAScript的一切以及ES6(又称ES2015)中添加的功能。

ECMAScript 2015,也称为ES6,是ECMAScript标准的基本版本。

与最新的标准修订相隔4年发布,ECMAScript 5.1,它也标志着从版本号转换为年份的变化。

因此不应该称为ES6(尽管每个人都这样称呼),而应该称为ES2015。

ES5的制定历经了10年,从1999年到2009年,因此它也是一次基本而非常重要的语言修订,但现在已经过去了很长时间,没有必要讨论ES5之前的代码是如何工作的了。

由于ES5.1和ES6之间过去了很长时间,因此发布版本中充满了重要的新功能和对JavaScript程序开发中推荐最佳实践的重大变化。要了解ES2015有多么基础,请记住,随着这个版本,规范文档从250页增加到了~600页。

本文描述了最重要的变化。

箭头函数

自引入以来,箭头函数改变了大多数JavaScript代码的外观(和工作原理)。

从视觉上看,这是一个简单而受欢迎的变化,从:

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

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

如果函数体只有一行代码,只需:

const something = () => doSomething()

此外,如果只有一个参数,可以写成:

const something = param => doSomething(param)

这并不是一个破坏性的变化,常规的function仍然像以前一样工作。

新的this作用域

箭头函数的this作用域是从上下文继承的。

对于常规的functionthis始终引用最近的函数,而对于箭头函数,解决了这个问题,您将不再需要编写var that = this

Promises

Promises(查看完整的Promises指南)使我们能够消除著名的“回调地狱”,尽管它们引入了更多的复杂性(这在ES2017中使用async解决了,这是一个更高级的构造函数)。

很多JavaScript开发人员在ES2015之前就已经使用Promise,并且有许多不同的库实现(例如jQuery、q、deferred.js、vow等),标准将其统一起来。

通过使用Promises,您可以将此代码重写为

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

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'))

生成器

生成器是一种特殊类型的函数,它具有暂停和恢复的能力,允许在此期间运行其他代码。

有关详细解释,请参阅完整的JavaScript生成器指南。

letconst

var传统上是函数作用域的。

let是一个新的变量声明,它是块级作用域的。

这意味着在for循环中,if内部或纯块内部声明的let变量不会“逃出”该块,而var将被提升到函数定义的顶部。

constlet非常相似,但是不可变

在JavaScript中,你会看到很少或几乎没有var声明了,只有letconst

特别是const非常常用,因为不变性非常受欢迎。

传统上,JavaScript是唯一一种原型继承的主流语言。从基于类的语言切换到JS的程序员发现它很费解,但是ES2015引入了类,它只是语法糖,但是改变了我们构建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')
tomCruise.hello()

(以上程序打印“Hello, I am Tom Cruise. I am an actor.“)

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

构造函数

类有一个特殊的方法,称为constructor,在通过new初始化类时调用该方法。

Super

可以使用super()引用父类。

取值器和存值器

可以声明属性的取值器:

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

存值器的编写方式相同:

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

模块

在ES2015之前,至少有3种竞争的模块标准,这导致社区的分裂:

  • AMD
  • RequireJS
  • CommonJS

ES2015将其标准化为一种通用格式。

导入模块

通过import ... from ...结构导入:

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

导出模块

您可以编写模块并使用export关键字将任何内容导出到其他模块:

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

模板字符串

模板字符串是一种创建字符串的新语法:

const aString = `A string`

它们提供了一种将表达式嵌入字符串的方式,通过${a_variable}语法有效地插入值:

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

您还可以执行更复杂的表达式:

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

并且字符串可以跨越多行:

const string3 = `Hey
this

string
is awesome!`

将其与ES2015之前如何处理多行字符串进行比较:

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

查看此文章,了解模板字符串的详细指南

默认参数

函数现在支持默认参数:

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

展开运算符

您可以使用展开运算符...展开数组、对象或字符串。

让我们从一个数组示例开始。给定

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 = (arg1, arg2) => {}
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

nameage包含所需的值。

该语法也适用于数组:

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

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

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

增强的对象字面量

在ES2015中,对象字面量获得了超级能力。

更简洁的语法来包含变量

不再需要编写

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

可以使用以下代码:

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

原型

可以使用以下代码指定原型:

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

动态属性

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

for-of循环

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

ES2015引入了for-of循环,它将forEach的简洁性与中断的能力结合起来:

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

//使用`entries()`以及获取索引
for (const [i, v] of ['a', 'b', 'c'].entries()) {
 console.log(i, v);
}

Map和Set

MapSet(及其各自的垃圾回收WeakMapWeakSet)是两种非常流行的数据结构的官方实现。

新的字符串方法

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

  • repeat()重复字符串指定的次数:'Ho'.repeat(3) //HoHoHo
  • codePointAt()处理无法由单个16位UTF-16单元表示的字符的Unicode代码

新的对象方法

ES6在对象命名空间下引入了几种静态方法: