TODO:这仅仅是一篇草稿 个人使用,内容有待完善不建议查看
TODO: 此文档还需完善请留言或联系作者
《ECMAScript入门》摘抄
ECMAScript 6简介
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了。
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)。
转码器
Babel转码器:
Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在现有环境执行。
Babel 的配置文件是.babelrc
,存放在项目的根目录下。使用 Babel 的第一步,就是配置这个文件。
Babel提供babel-cli
工具,用于命令行转码。
Babel 提供一个REPL在线编译器,可以在线将 ES6 代码转为 ES5 代码。转换后的代码,可以直接作为 ES5 代码插入网页运行。
Traceur转码器:
Google 公司的Traceur转码器,也可以将 ES6 代码转为 ES5 代码。
Traceur 允许将 ES6 代码直接插入网页。首先,必须在网页头部加载 Traceur 库文件。
let和const命令
let:
使用let
,声明的变量仅在块级作用域内有效。(之前在js中是没有块级作用域的)。
let
实际上为 JavaScript 新增了块级作用域。
使用let可以避免下面的场景:
- 第一种场景,内层变量可能会覆盖外层变量。
- 第二种场景,用来计数的循环变量泄露为全局变量。
const:
const
声明一个只读的常量。一旦声明,常量的值就不能改变。
const
的作用域与let
命令相同:只在声明所在的块级作用域内有效。
如果const用于引用类型,则说明该指针是常量。
ES6为了保持兼容性,var
命令和function
命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let
命令、const
命令、class
命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。
变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
注意:这里重点是赋值。
解构允许使用模式匹配进行绑定,并支持匹配数组和对象。
数组的解构赋值
|
|
|
|
本质上,这种写法属于"模式匹配",只要等号两边的模式相同,左边的变量就会被赋予对应的值。
事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。
默认值
|
|
对象的解构赋值
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
|
|
字符串的解构赋值
|
|
函数参数的解构赋值
|
|
|
|
用途:
- 交换变量的值:
[x,y]=[y,x];
- 从函数返回多个值:
return [1,2,3];
- 函数参数的定义
- 提取Json数据:尤其有用
- 函数参数的默认值
- 遍历Map结构
字符串的扩展
ES6 加强了对 Unicode 的支持,并且扩展了字符串对象。
模板字符串
传统JS,输出模板通常使用下面的写法,通过 加号 相连:
|
|
而利用ES6的模板字符串可以这样解决:(类似shell中的字符串)
|
|
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
|
|
正则的扩展
略
数值的扩展
ES6 在Number
对象上,新提供的方法:
Number.isFinite()
用来检查一个数值是否为有限的(finite)。
Number.isNaN()
用来检查一个值是否为NaN
。
ES2016 新增了一个指数运算符(**
)。
函数的扩展
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。(之前是不能这样做的)
参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。
|
|
参数默认值可以与解构赋值的默认值,结合起来使用。
参数的位置
通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。
作用域
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。
|
|
rest参数
ES6 引入 rest 参数(形式为...变量名
),用于获取函数的多余参数,这样就不需要使用arguments
对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
注意,rest 参数之后不能再有其他参数
|
|
箭头函数
另外请参考:箭头函数 - JavaScript | MDN ⭐
ES6 允许使用"箭头"(=>
)定义函数。
|
|
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
|
|
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return
语句返回。
|
|
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
|
|
箭头函数的一个用处是简化回调函数。
|
|
箭头函数注意点
(1)函数体内的this
对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new
命令,否则会抛出一个错误。
(3)不可以使用arguments
对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield
命令,因此箭头函数不能用作 Generator 函数。
上面四点中,第一点尤其值得注意。this
对象的指向是可变的,但是在箭头函数中,它是固定的。
|
|
上面代码中,setTimeout
的参数是一个箭头函数,这个箭头函数的定义生效是在foo
函数生成时,而它的真正执行要等到100毫秒后。如果是普通函数,执行时this
应该指向全局对象window
,这时应该输出21
。但是,箭头函数导致this
总是指向函数定义生效时所在的对象(本例是{id: 42}
),所以输出的是42
。
还有很多内容,略
数组的扩展
略
对象的扩展
略
…
Promise对象
这个也是重点
Promise 是异步编程的一种解决方案,比传统的解决方案,回调函数和事件,更合理和更强大。
所谓Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
Promise
对象有以下两个特点:
-
对象的状态不受外界影响。
Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise
这个名字的由来,它的英语意思就是"承诺",表示其他手段无法改变。后文的
resolved
统一只指fulfilled
状态 -
一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise
对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise
对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是:如果你错过了它,再去监听,是得不到结果的。
有了Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供统一的接口,使得控制异步操作更加容易。
Promise
也有一些缺点:
- 首先,无法取消
Promise
,一旦新建它就会立即执行,无法中途取消。 - 其次,如果不设置回调函数,
Promise
内部抛出的错误,不会反应到外部。 - 第三,当处于
pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
then()
方法
Promise
实例生成以后,可以用then
方法分别指定resolved
状态(第一个参数)和rejected
状态(第二个参数 [可选])的回调函数。
|
|
then
方法返回的是一个新的Promise
实例(注意,不是原来那个Promise
实例)。因此可以采用链式写法,即then
方法后面再调用另一个then
方法。
|
|
resolve
和reject
是两个函数,由 JavaScript 引擎提供,不用自己部署。
catch()
方法
catch()
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
Promise实例
- 加载图片
- Ajax 操作
Promise对象 – JavaScript 标准参考教程(alpha)
你不知道的JavaScript You-Dont-Know-JS
Class的基本语法
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class
关键字,可以定义类。
基本上,ES6 的class
可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
|
|
注意,定义"类"的方法的时候,前面不需要加上function
这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。
类必须使用new
调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new
也可以执行。
Class表达式
与函数一样,类也可以使用表达式的形式定义。
|
|
Class的继承
|
|
上面代码中,constructor
方法和toString
方法之中,都出现了super
关键字,它在这里表示父类的构造函数,用来新建父类的this
对象。
子类必须在constructor
方法中调用super
方法,否则新建实例时会报错。这是因为子类没有自己的this
对象,而是继承父类的this
对象,然后对其进行加工。如果不调用super
方法,子类就得不到this
对象。
如果子类没有定义constructor
方法,这个方法会被默认添加,代码如下。也就是说,不管有没有显式定义,任何一个子类都有constructor
方法。
Module的语法
模块功能主要由两个命令构成:export
和import
。export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
export命令
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export
关键字输出该变量。export
还可用于函数和类。
示例:
|
|
|
|
|
|
|
|
|
|
import命令
|
|
export default命令
从前面的例子可以看出,使用import
命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。
为了给用户提供方便,可以用export default
命令,为模块指定默认输出。
|
|
其他模块加载该模块时,import
命令可以为该匿名函数指定任意名字。
|
|