ES6指南
ECMAScript是JavaScript基于的标准,通常缩写为ES。了解关于ECMAScript的一切以及ES6(又称ES2015)中添加的功能。
- 箭头函数
- 新的
this
作用域 - Promises
- 生成器
let
和const
- 类
- 模块
- 模板字符串
- 默认参数
- 展开运算符
- 解构赋值
- 增强的对象字面量
- for-of循环
- Map和Set
- 新的字符串方法
- 新的对象方法
ECMAScript 2015,也称为ES6,是ECMAScript标准的基本版本。
与最新的标准修订相隔4年发布,ECMAScript 5.1,它也标志着从版本号转换为年份的变化。
因此不应该称为ES6(尽管每个人都这样称呼),而应该称为ES2015。
ES5的制定历经了10年,从1999年到2009年,因此它也是一次基本而非常重要的语言修订,但现在已经过去了很长时间,没有必要讨论ES5之前的代码是如何工作的了。
由于ES5.1和ES6之间过去了很长时间,因此发布版本中充满了重要的新功能和对JavaScript程序开发中推荐最佳实践的重大变化。要了解ES2015有多么基础,请记住,随着这个版本,规范文档从250页增加到了~600页。
本文描述了最重要的变化。
箭头函数
自引入以来,箭头函数改变了大多数JavaScript代码的外观(和工作原理)。
从视觉上看,这是一个简单而受欢迎的变化,从:
1 | const something = function something() { |
到
1 | const something = () => { |
如果函数体只有一行代码,只需:
1 | const something = () => doSomething() |
此外,如果只有一个参数,可以写成:
1 | const something = param => doSomething(param) |
这并不是一个破坏性的变化,常规的function
仍然像以前一样工作。
新的this
作用域
箭头函数的this
作用域是从上下文继承的。
对于常规的function
,this
始终引用最近的函数,而对于箭头函数,解决了这个问题,您将不再需要编写var that = this
。
Promises
Promises(查看完整的Promises指南)使我们能够消除著名的“回调地狱”,尽管它们引入了更多的复杂性(这在ES2017中使用async
解决了,这是一个更高级的构造函数)。
很多JavaScript开发人员在ES2015之前就已经使用Promise,并且有许多不同的库实现(例如jQuery、q、deferred.js、vow等),标准将其统一起来。
通过使用Promises,您可以将此代码重写为
1 | setTimeout(function() { |
如
1 | const wait = () => new Promise((resolve, reject) => { |
生成器
生成器是一种特殊类型的函数,它具有暂停和恢复的能力,允许在此期间运行其他代码。
有关详细解释,请参阅完整的JavaScript生成器指南。
let
和const
var
传统上是函数作用域的。
let
是一个新的变量声明,它是块级作用域的。
这意味着在for
循环中,if
内部或纯块内部声明的let
变量不会“逃出”该块,而var
将被提升到函数定义的顶部。
const
与let
非常相似,但是不可变。
在JavaScript中,你会看到很少或几乎没有var
声明了,只有let
和const
。
特别是const
非常常用,因为不变性非常受欢迎。
类
传统上,JavaScript是唯一一种原型继承的主流语言。从基于类的语言切换到JS的程序员发现它很费解,但是ES2015引入了类,它只是语法糖,但是改变了我们构建JavaScript程序的方式。
现在继承变得非常简单,并且与其他面向对象编程语言类似:
1 | class Person { |
(以上程序打印“*Hello, I am Tom Cruise. I am an actor.*“)
类没有显式的类变量声明,但必须在构造函数中初始化任何变量。
构造函数
类有一个特殊的方法,称为constructor
,在通过new
初始化类时调用该方法。
Super
可以使用super()
引用父类。
取值器和存值器
可以声明属性的取值器:
1 | class Person { |
存值器的编写方式相同:
1 | class Person { |
模块
在ES2015之前,至少有3种竞争的模块标准,这导致社区的分裂:
- AMD
- RequireJS
- CommonJS
ES2015将其标准化为一种通用格式。
导入模块
通过import ... from ...
结构导入:
1 | import \* from 'mymodule' |
导出模块
您可以编写模块并使用export
关键字将任何内容导出到其他模块:
1 | export var number = 2 |
模板字符串
模板字符串是一种创建字符串的新语法:
1 | const aString = `A string` |
它们提供了一种将表达式嵌入字符串的方式,通过${a_variable}
语法有效地插入值:
1 | const joe = 'test' |
您还可以执行更复杂的表达式:
1 | const string = `something ${1 + 2 + 3}` |
并且字符串可以跨越多行:
1 | const string3 = `Hey |
将其与ES2015之前如何处理多行字符串进行比较:
1 | var str = 'One\n' + |
默认参数
函数现在支持默认参数:
1 | const someFunction = function(index = 0, testing = true) { /\* ... \*/ } |
展开运算符
您可以使用展开运算符...
展开数组、对象或字符串。
让我们从一个数组示例开始。给定
1 | const a = [1, 2, 3] |
您可以使用以下代码创建一个新数组:
1 | const b = [...a, 4, 5, 6] |
您还可以使用以下代码创建数组的副本:
1 | const c = [...a] |
这对对象也适用。使用以下代码克隆对象:
1 | const newObj = { ...oldObj } |
对于字符串,展开运算符将创建一个包含字符串中每个字符的数组:
1 | const hey = 'hey' |
展开运算符有一些非常有用的应用。最重要的应用之一是以非常简单的方式使用数组作为函数参数:
1 | const f = (arg1, arg2) => {} |
(过去,可以使用f.apply(null, a)
来完成,但这并不那么好看和可读)
解构赋值
给定一个对象,您可以提取出其中的一些值,并将它们放入命名变量中:
1 | const person = { |
name
和age
包含所需的值。
该语法也适用于数组:
1 | const a = [1,2,3,4,5] |
此语句通过从数组a
中获取索引为0、1、4的项来创建3个新变量:
1 | const [first, second, , , fifth] = a |
增强的对象字面量
在ES2015中,对象字面量获得了超级能力。
更简洁的语法来包含变量
不再需要编写
1 | const something = 'y' |
可以使用以下代码:
1 | const something = 'y' |
原型
可以使用以下代码指定原型:
1 | const anObject = { y: 'y' } |
super()
1 | const anObject = { y: 'y', test: () => 'zoo' } |
动态属性
1 | const x = { |
for-of循环
ES5在2009年引入了forEach()
循环。虽然好用,但它们没有提供中断的方法,就像for
循环一样。
ES2015引入了for-of循环,它将forEach
的简洁性与中断的能力结合起来:
1 | //遍历值 |
Map和Set
Map和Set(及其各自的垃圾回收WeakMap和WeakSet)是两种非常流行的数据结构的官方实现。
新的字符串方法
任何字符串值都有一些新的实例方法:
repeat()
重复字符串指定的次数:'Ho'.repeat(3) //HoHoHo
codePointAt()
处理无法由单个16位UTF-16单元表示的字符的Unicode代码
新的对象方法
ES6在对象命名空间下引入了几种静态方法:
Object.is()
用于判断两个值是否相同的值Object.assign()
用于浅复制对象Object.setPrototypeOf
设置对象原型
tags: [“JavaScript”, “ES6”, “ECMAScript”, “Promises”, “Generators”, “Classes”, “Modules”]