众所周知,
ES6
虽然有着很多的兼容性问题。(使用Babel
转码解决)。但是很多开发者已经在项目中用了。就算现在不打算用,为了看懂别人代码你也得懂一些ES6
语法了。本文开始讲不再讲ES6
和JavaScript
的关系之类的东西。只是介绍ES6
语法。
1. 声明变量
1). 现有的声明方式
以前声明变量只有一种方法,那就是使用var
关键字。ES6
对声明进行了扩展,现在有三种声明方式:
var
:variable
,可以理解为变量的意思let
: 在英文中是 让 的意思,也可以理解为一种声明的意思const
:在英文中是 常量的意思,在ES6
中也是用来声明 常量的,可以理解为不变的量。
2). var
声明
var
在es6
中是用来声明全局变量的,可以先做一个最简单的实例,用var
声明一个变量a,然后用console.log
输出。
var a = '我是a'
console.log(a)
可以看到我是a
的信息在控制台已经打印出来了。那么如何理解它的作用是声明全局变量呢,可以用匿名函数进行一个包裹,然后在匿名函数中调用这个a变量,看看是否能正常输出
window.onload = function() {
console.log(a)
}
可以看到控制台正常输出a
的值,这证明var
确实是全局的。如果这个不够直观说明var
是全局声明,还可以用区块的方式进行调用,如下:
var a = 2
{
var a = 3
}
console.log(a)
这个时候打印出来的值是多少?对。 是3,因为var
是全局声明的。
3). let
局部声明
通过以上的例子,已经对var
有一些简单了解,跟它对应的let
,它是局部变量声明,如上面的例子
var a = 2
{
let a = 3
}
console.log(a) // 2
此时,控制台输出的值是2,如果只在区块声明,没在外部声明,就会报错
{
let a = 3
}
console.log(a)
此时输出a将会报错。上面的例子说明了let
是局部变量,只在区块内起作用,外部是不可以调用的。
可能有些人会觉得var
比let
好用,其实let
是防止你的数据污染的。在项目中是非常有用的。例如一个for
循环案例
for(var i = 0; i < 5; i++) {
console.log(i)
}
console.log(i)
此时控制台会输出0,1,2,3,4,最后输出5,说明区块里声明的i在全局中还是可以访问的。这样会污染全局变量。如果改成let
就会解决这个问题
for(let i = 0; i < 5; i++) {
console.log(i)
}
console.log(i)
此时外部的i将会报错。
4). const
生成常量
const
的特性就是从声明开始,这个变量是始终不变的。如下:
const a = 1
console.log(a)
a = 2
console
会正常输出,但是下面a = 2
就会报错。因为const
声明的变量值不能修改。
2. 变量的解构赋值
ES6
允许按照一定模式,从数组和对象中提取值,这就是解构,解构赋值在实际开发中可以大大减少代码量,并且使程序结构更清晰。
1). 数组的解构赋值
以前,为变量赋值,只能直接指定值,如下代码:
let a = 0;
let b = 1;
let c = 2
现在可以用数组解构的方式来进行赋值。
let [a, b, c] = [1, 2, 3]
上面的代码表示,可以从数组中提取值,按照位置的对应关系对变量赋值。
1: 数组模式和赋值模式必须统一
可以简单的理解为等号左边和等号右边的形式要统一,如果不统一解构将失败
let [a, [b, c], d] = [1, [2, 3], 4]
如果两边不一致,就可能会undefined或者直接报错。
2: 解构的默认值
解构赋值是可以使用默认值的,例如:
let [foo = true] = []
console.log(foo) // true
上面的例子数组中只有一个值,下面是多个值的数组,并且有默认值
let [a, foo = '我是foo'] = [1]
console.log(a + foo) // 1我是foo
需要注意的是undefined
和null
的区别
let [a, b = '我是b'] = ['我是a', undefined]
console.log(a + b) // 我是a我是b
let [c, d = '我是d'] = ['我是c', null]
console.log(c + d) // 我是cnull
undefined
表示什么都没有,null
表示有值,但是值是空null
3. 对象的解构赋值
对象也可以使用解构赋值
let {foo, bar} = {foo: '我是foo', bar: '我是bar'}
console.log(foo + bar) // 我是foo我是bar
对象的解构赋值和数组解构赋值有一点不一样:数组的元素是按次序排列的,变量的取值取决于它的位置决定;而对象是没有次序的,所以变量必须与属性同名,才能取到正确的值。
4. 圆括号的使用
如果在解构之前就定义了变量,这时候再解构就会出现问题,以下是错误代码
let foo
{foo} = {foo: '我是foo'}
console.log(foo) // 报错
以上代码会报错,要使它正常运行,只要在解构的语句外边加一个圆括号就可以了
let foo
({foo}) = {foo: '我是foo'}
console.log(foo) // 我是foo
5. 字符串解构
字符串也是可以解构的,这是因为,此时字符串被转换成了一个类似数组的对象
const [a, b, c, d, e, f] = 'abcdef'
console.log(a) // a
console.log(b) // b
console.log(c) // c
console.log(d) // d
console.log(e) // e
console.log(f) // f
3. 扩展运算符和rest运算符
下面介绍
扩展运算符
和rest运算符
,都是...(三个点)
。它的作用是为我们解决参数和对象数组未知情况下的开发,让代码更加的简洁易懂。
1). 对象扩展运算符
编写一个方法时,我们允许传入的参数是不确定的,这时候可以使用对象扩展符来作为参数,如下
function test(...arg) {
console.log(arg[0])
console.log(arg[1])
console.log(arg[2])
console.log(arg[3])
}
test(1, 2, 3) // 1, 2, 3, undefined
此时上面的代码在控制台输出1, 2, 3, undefined
,说明是可以传入多个值,就算方法中引用了也不会报错。
2). 数组扩展运算符
首先,可以声明两个数组arr1
和arr2
,然后把arr1
的值赋给arr2
,然后改变arr2
的值,你会发现arr1
的值也发生了改变,是因为这是对 内存堆栈 的引用,而不是真正的赋值。
let arr1 = ['a', 'b', 'c']
let arr2 = arr1
console.log(arr2) // ['a', 'b', 'c']
arr2.push('d')
console.log(arr1) // ['a', 'b', 'c', 'd']
以上代码会在控制台依次输出: ['a', 'b', 'c']
和 ['a', 'b', 'c', 'd']
这不是我们想要的结果,这个时候就需要利用数组的扩展运算符解决这个问题。现在对代码进行改造,如下:
let arr1 = ['a', 'b', 'c']
let arr2 = [...arr1]
console.log(arr2) // ['a', 'b', 'c']
arr2.push('d')
console.log(arr2) // ['a', 'b', 'c', 'd']
console.log(arr1) // ['a', 'b', 'c']
此时在控制台预览,可以看到arr1
的值并没有改变,这就是数组扩展运算符的用法。
3). rest运算符
如果你已经很好的掌握了对象扩展运算符,那么理解rest运算符
并不难,因为它们有很多相似之处,很多时候甚至不用刻意去区分,它也用...
来表示。如下例子
function test(first, ...arg) {
console.log(arg.length) // 5
}
test(0, 1, 2, 3, 4, 5)
此时控制台打印出7.说明arg
里面有7个数组元素,这就是rest运算符
的基本用法。
如何循环输出rest运算符
使用for...of
循环来进行打印出arg
的值
function test(first, ...arg) {
for (let val of arg) {
console.log(val) // 依次输出1, 2, 3, 4, 5
}
}
test(0, 1, 2, 3, 4, 5)
上面的代码执行结果是:依次输出1, 2, 3, 4, 5
for...of
循环可以避免我们开拓内存空间,增加代码执行效率,所以建议在开发中使用for...of
循环。
4. 字符串模板
ES6
对字符串新增的操作中,最重要的就是字符串模板
,它可以使我们不再需要拼接变量,而且支持模板里面有简单计算操作。
1). 字符串模板
首先看一个在ES5
下字符串的拼接
let name = 'john'
let str = '我是' + name + ',很高兴和你见面.'
console.log(str) // 我是john, 很高兴和你见面.
ES6
必须用+str+
的形式进行拼接,这样很麻烦且容易出错。ES6
新增了字符串模板。可以很好的解决这个问题,变量使用${xxx}
来表示。如下
let name = 'john'
// 注意此处'单引号必须变成特殊符号`, 就是Esc下面的那个键
let str = `我是${name}, 很高兴和你见面.`
可以看到,浏览器和上面的代码返回一样的结果,而且里面可以支持HTML
标签。可以试着输入一些
let name = 'john'
let str = `<b>我是${name}, 很高兴和你见面.</b>`
也可以支持运算
let a = 1
let b = 2
let result = `${a + b}`
console.log(result) // 3
2). 字符串查找
ES6
新增了字符串的查找功能,而且支持中文。
ES5
的查找是否存在的写法,其实并不实用,给了索引位置,还要自己确定是否一样
let str = 'john'
let txt = '我是john,很高兴见到你'
console.log(txt.indexOf(str)) // 2
网页中输出2,还要自己判断
ES6
中使用includes
就可以判断,不再返回索引值。
let str = 'john'
let txt = '我是john,很高兴见到你'
console.log(txt.includes(str)) // true
// 判断开头是否存在
console.log(txt.startsWith(str)) // false
// 判断结尾是否存在
console.log(txt.endsWith(str)) // false
3). 复制字符串
console.log('john|'.repeat(3)) // 'john|john|john|'
5. ES6
数字操作
1). 二进制
二进制的英文是Binary, 二进制的开始是0(零),第二个位置是b(注意这里大小写都可以实现),然后跟上二进制的值就可以了
let binary = 0B010101
console.log(binary) // 21
2). 八进制
八进制的英文是Octal, 也是从 0(零) 开始的,第二个位置的是O(欧), 然后跟上八进制的值就好了
let b = 0o666
console.log(b) // 438
3). 数字的判断和转换
使用Numbel.isFinite()
来进行数字验证,只要是数字,不论是浮点还是整数都会返回true
,其他返回false,并且它不会强制转换类型
let a = 11/4
console.log(Number.isFinite(a)) // true
console.log(Number.isFinite('jo') // false
console.log(Number.isFinite(NaN)) // false
console.log(Number.isFinite(undefined)) // false
console.log(Number.isFinite(true)) // false
4). NaN验证
NaN
是特殊的非数字,使用Number.isNaN
来进行验证。
console.log(Number.isNaN(NaN)) // true
console.log(Number.isNaN('NaN') // flase
5). 判断是否为整数
console.log(Number.isInteger(123.1)) // false
console.log(Number.isInteger(true)) // false
6). 整数以及浮点型相互转换
let a = '9.1'
console.log(Number.parseInt(a)) // 9
console.log(Number.parseFloat(a)) // 9.1
7). 整数取值范围的操作
整数的操作是有一个取值范围的。它的取值范围是2的53次方,可以先看一下这个数字是多少
let a = Math.pow(2, 53)-1
console.log(a) // 9007199254740991
开发中,可能会超过这个值,所以要进行判断。ES6
提供了一个常数,叫做最大安全数和最小安全数
// 最大安全数
console.log(Number.MAX_SAFE_INTEGER) // 9007199254740991
// 最小安全数
console.log(Number.MIN_SAFE_INTEGER) // -9007199254740991
8). 安全整数判断
let a = Math.pow(2, 53)-1
console.log(Number.isSafeInteger(a)) // true
console.log(Number.isSafeInteger(Math.pow(2, 54)-1)) // false
6. ES6
中新增的数组知识
1). JSON
数组格式的转换
JSON
的数组格式就是为了前端快速的把JSON
转换成数组的一种格式
let json = {
'0': 'john',
'1': '我是a',
'2': '我是b',
length: 3
}
以上是一个标准的JSON
数组格式,跟普通的JSON
对比最后多了一个length
属性。只要是这种特殊的JSON
格式都可以使用ES6
的语法转变成真正的数组。可以使用Array.from(xxx)
来将他们转换成数组。
let json = {
'0': 'john',
'1': '我是a',
'2': '我是b',
length: 3
}
let arr = Array.from(json)
console.log(arr) // ['john', '我是a', '我是b']
2). Array.of()
它负责把一堆文本或者变量转换成数组。如下
let arr = Array.of(3, 4, 5, 6)
console.log(arr) // [3, 4, 5, 6]
console.log(Array.of('我是a', '我是b', '我是c')) // ['我是a', '我是b', '我是c']
3. find()
实例方法
所谓的实例方法就是并不是以Array
对象开始的。而是必须有一个已经存在的数组,然后会用的方法,这就是实例方法。下面的find()
方法是从数组中查找。在find()
中需要传入一个匿名函数,函数可以接收3个参数,如下:
- value: 表示当前查找的值
- index: 表示当前查找的数组索引
- arr: 表示当前数组
在函数中如果找到符合条件的数组元素就进行return
,并停止查找。如下代码
let arra = [1, 2, 3, 4, 5, 6, 7, 8]
console.log(arra.find(function(value, index, arr) {
return value > 5
})) // 6
此时控制台返回6.注意,这个方法只返回第一个符合条件的值。如果找不到会返回undefined
。
5). fill()
fill()
也是一个实例方法,它的作用是把数组进行填充,接收3个参数,第一个参数是填充的变量,第二个是开始填充的位置,第三个是填充结束的位置
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
arr.fill('john', 2, 5)
console.log(arr) // [0, 1, 'john', 'john', 'john', 5, 6, 7, 8, 9]
6). 数组的遍历-for...of
这种形式要比ES5
的for
循环要简单且高效。
let arr = ['a', 'b', 'c']
for (let item of arr) {
console.log(item) // 依次输出a, b, c
}
7). for...of
输出索引,值和同时输出
// 输出值
let arr = ['a', 'b', 'c']
for (let item of arr){
console.log('值: ' + item)
}
// 输出索引
for (let index of arr.keys()){
console.log('index: ' + index)
}
// 输出值加索引
for (let [index, item] of arr.entries()) {
console.log('index: ' + index + ', 值: ' + item)
}
8). entries()
实例方法
entries
实例方法生成的是Iterator
形式的数组,这种形式的好处就是可以在需要的时候用next()
手动跳转到下一个值。如下代码
let arr = ['a', 'b', 'c']
let list = arr.entries()
console.log(list.next().value) // a
console.log(list.next().value) // b
console.log(list.next().value) // c
8. ES6
中的箭头函数和扩展
箭头函数可能是
ES6
中最重要的部分了
首先回顾一下ES5
中函数的写法
function add(a, b) {
return a + b
}
add(1, 2) // 3
声明了一个add()
,然后传入a
和b
的值,返回a + b
的值。控制台打印的结果为3。
1). 函数默认值
ES6
中增加了默认值的操作,具体使用方式如下
function add(a, b = 2) {
return a + b
}
add(1) // 3
此时只需要传递一个参数也是可以运行的。
2). 抛出错误异常
在日常开发中,经常会看到一些第三方库会抛出一些异常。例如: Vue
中如果v-for
没有key
值,就会报错。其实是使用了ES6
中的throw new Error(xxx)
function add(a, b = 2) {
if (a === 0) {
throw new Error('This is error')
}
return a + b
}
add(1)
3). 块级作用域的严格模式
在之前的ES5
开发过程中经常会使用严格模式来进行开发。但是必须写在代码的最上面。相当于全局使用,但是在ES6
中允许写在了函数体内,相当于针对本函数来使用。
function add(a, b = 2) {
'use strict'
if (a === 0) {
throw new Error('This is Error')
}
return a + b
}
add(1)
上面的代码可能会报错,这是ES6
的一个坑,错误的原因是 ES6
规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式。解决办法是取消默认值。这时候就会正常运行。
function add(a, b) {
'use strict'
if (a === 0) {
throw new Error('This is Error')
}
return a + b
}
add(1, 2)
4). 获取需要传递的参数个数
function add(a, b) {
return a + b
}
add(1, 2)
console.log(add.length) // 2
此时控制台打印出了2,但是如果加上参数默认值的话,这时候add.length
的值就变成了1,也就是说它得到的必须是传入的参数。
5). 箭头函数
先来看一个简单的箭头函数例子
var add = (a, b) => a + b
onsole.log(add(1, 2)) // 3
在箭头函数中,方法体内如果不超过一句话,就可以省略{}
和里面的return
语句。如果超过1句话,那就必须在方法体外边加入{}
符号。例如下面的代码
var add = (a, b) => {
console.log(a, b)
return a + b
}
另外,普通函数和箭头函数的this大不一样,普通函数的this值往往是根据调用它的函数环境确定。而箭头函数this是执行时所在的环境。
// 普通函数
var name = '123'
var obj = {
name: '我是obj的name',
sayName: function() {
console.log(this.name) // 我是obj的name
}
}
obj.sayName() // 普通函数的this可以理解为.号前面的对象。
// 箭头函数
var name = '123'
var obj = {
name: '我是obj的name',
sayName: () => {
console.log(this.name) // 123
}
}
obj.sayName()
还有一点,箭头函数中不可加new
,也就是说箭头函数不能当做构造函数使用。
9. ES6
中的函数和数组补漏
1). 对象的函数解构
例如函数和对象的解构赋值结合使用,可以在开发中将后端返回的值直接参数使用
let json = {
a: 'a',
b: 'b'
}
function add({a, b = '默认值'}) {
console.log(a, b) // a, b
}
add(json)
2). 数组的函数解构
let arr = ['a', 'b', 'c']
function add(a, b, c) {
console.log(a, b, c) // a, b, c
}
add(...arr)
3). in
的用法
in
用来判断对象或者数组中是否存在某个属性,
// 对象判断
let obj = {
a: '我是a',
b: '我是b'
}
console.log('a' in obj) // true
// 数组判断
// es5中, 弊端,空值也会判断有值
let arr = [, , , , ,]
console.log(arr.length) // 5
// es6 中, 注意下面的0指的是数组下标位置是否为空
console.log(0 in arr) // false, 代表下标为0的没有
let arr1 = ['a', 'b']
console.log(0 in arr1) // true
4). 数组的遍历方法
forEach
: 特点会自动忽略为空的数组元素,相当于直接筛空。
let arr = ['a', 'b', 'c']
arr.forEach(() => console.log(index, val)) // 依次输出 0 'a' -> 1 'b' -> 2 'c'
filter
:用于筛选,返回的是符合条件的新数组。不会改变原数据
let arr = [1, 2, 3, 4, 5]
console.log(arr.filter(x => x > 3))
some
:如果该函数对任一项返回true。则最后返回值为true。
let arr = [1, 2, 3, 4, 5]
arr.some(x => console.log(x > 3)) // false, false, false, true, true
map
:通过指定函数处理数组的每一个元素,并返回处理后的数据。不会改变原数组。
let arr = [1, 2, 3, 4, 5]
console.log(arr.map(x => x))
join
:替换数组里的分隔符,不会改变原数组
let arr = [1, 2, 3, 4, 5]
console.log(arr.join('|')) // '1|2|3|4|5'
toString
:将数组转换为字符串,不会改变原数组。
console.log(['a', 'b', 'c'].toString()) // 'a,b,c'
10. ES6
中的对象
1). 对象赋值
ES6
允许把声明的变量直接赋值给对象
let a = 'a'
let b = 'b'
var obj = {a, b}
console.log(obj) // {a: 'a', b: 'b'}
2). 对象Key
值创建
有的时候key值可能是动态的。
let key = 'name'
var obj = {
[key]: 'web'
}
console.log(obj.name) // 'web'
3). 自定义对象方法
var obj = {
add: function (a, b) {
return a + b
}
}
console.log(obj.add(1, 2)) // 3
4). Object.is()
对象比较
以前ES5
的对象比较方法经常使用 ===
来判断。
var obj1 = {name: 'a'}
var obj2 = {name: 'a'}
console.log(obj1.name == obj2.name} // true
ES6
提供了is
方法进行比较,并且is
是严格相等.
var obj1 = {name: 'a'}
var obj2 = {name: 'b'}
console.log(Object.is(obj1.name, obj2.name)) // true
5). Object.assign()
合并对象
操作数组可以使用Array.concat()
合并。对象则使用Object.assign()
合并
var a = {a: 'a'}
var b = {b: 'b'}
var c = {c: 'c'}
let d = Object.assign(a, b, c)
console.log(d) // {a: 'a', b: 'b', c: 'c'}
11. Symbol
在对象中的使用
Symbol
是ES6
中新引入的基础数据类型值。代表是独一无二的值。最大的用法是用来定义对象的唯一属性。
1). 声明Symbol
var a = new String()
var b = new Number()
var c = new Boolean()
var d = new Array()
var e = new Object()
var f = Symbol()
console.log(typeof d) // object
2). Symbol
在对象中的应用
var s = Symbol()
var obj = {
[s]: '我是s'
}
console.log(obj[s])
obj[s] = '我是修改后的'
console.log(obj[s])
3). Symbol
对象元素的保护作用
在对象中有很多值,但是循环输出时,并不希望全部输出,可以使用Symbol
进行保护
// 没有保护的写法
var obj = {name: 'a', age: 18, web: 'web'}
for (let item in obj) {
console.log(obj[item]) // 依次输出a, 18, web
}
// Symbol保护写法
var obj = {name: 'a', web: 'web'}
var age = Symbol()
obj[age] = 18
for (let item in obj) {
console.log(obj[item]) // a, web
}
12. Set
和WeakSet
数据结构
本节讲
Set
数据结构,注意它不是数据类型,而是数据结构。它的数据结构是以数组的形式构建的。
1). Set
的声明
Set
和Array
的区别是Set
不允许内部有重复的值,如果有只显示一个,相当于去重。虽然它很像数组,但它并不是数组。
let setArr = new Set(['a', 'b', 'c'])
console.log(setArr) // Set {'a', 'b', 'c'}
2). Set
的增删查
追加add
let setArr = new Set(['a', 'b', 'c'])
setArr.add('d')
console.log(setArr) // Set {'a', 'b', 'c', 'd'}
删除delete
let setArr = new Set(['a', 'b', 'c'])
setArr.delete('a')
console.log(setArr) // Set {'b', 'c', 'd'}
查找has
,返回的是true, false
let setArr = new Set(['a', 'b', 'c'])
console.log(setArr.has('a')) // true
清除clear
let setArr = new Set(['a', 'b', 'c'])
setArr.clear()
console.log(setArr) // true
3). set
的for...of
循环
let setArr = new Set(['a', 'b', 'c'])
for (let item of setArr) {
console.log(item) // 依次输出a, b, c
}
size
属性:可以获得Set
值的数量。
let setArr = new Set(['a', 'b', 'c'])
console.log(setArr.size) // 3
4). forEach
循环
let setArr = new Set(['a', 'b', 'c'])
setArr.forEach(value = > console.log(value)) // 依次输出a,b,c
5). WeakSet
它与Set
类似,都是不重复的值的集合,但是和Set
有两点不同:
WeakSet
的成员只能是对象WeakSet
的对象都是弱引用
即WeakSet
中对对象的引用不会被考虑进垃圾回收机制,即只要没有其他的对象引用该对象,则该对象就会被回收,而不管它是否存在于WeakSet
.(因此,WeakSet
适合临时存放一组对象和跟对象绑定的信息)
何为弱引用
即:如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象是否还在该弱引用的结构中。
弱引用对象不可遍历。
let weakobj = new WeakSet()
let obj = {a: 'a', b: 'b'}
weakobj.add(obj)
console.log(weakobj)
13. map
数据结构
map
也是ES6
新加的数据结构,在一些构建工具中是非常喜欢用map
这种数据结构来进行配置的。因为map
是一种灵活、简单的适合一对一查找的数据结构。
1). JSON
和 map
格式的对比
// 普通json, 采用对象模拟json
let json = {
name: 'john',
age: 18
}
console.log(json.name) // john
但是这种反应速度要低于数组和map
结构。而且map
的灵活性更好,可以看成是一种特殊的键值对,但是key
可以设置成数组,值也可以是字符串,让它不规律对应起来。
let json = {
name: 'john',
age: 18
}
console.log(json.name) // john
// map
var map = new Map()
map.set(json, 'iam')
console.log(map) // {json对象: iam}
// map
var map = new Map()
map.set('iam', json)
console.log(map) // {iam: json对象}
2). Map
的增删查
新增已经在上面写过
Get
取值
console.log(map.get(json)) // iam
delete
删除
map.delete(json)
size
数量
console.log(map.size)
has
查找是否存在
console.log(map.has('a'))
clear
清除所有
map.clear()
15. Promise
对象的使用
Promise
的出现解决了回调地狱的问题,在使用ES5
的时候,在多层嵌套回调时,写完的代码层次过多,很难进行维护和二次开发,因此Promise
应运而生,完美的解决了这个问题,它其实可以理解为一种承诺。当它成功时执行一些代码,失败时执行一些代码。
1. Pormise
的基本用法
Promise
执行多步操作非常好用,我们可以模拟一个多步操作的过程,以吃饭为例。要想在家吃饭,可以分为3步。
- 洗菜做饭
- 坐下来吃饭
- 收拾桌子洗碗
整个过程肯定是有顺序的,必须保证上一步完成,才能顺利进行下一步。下面就用Promise
的方式来实现。
let state = 1
function step1 (resolve, reject) {
console.log('1. 开始 - 洗菜做饭')
if (state == 1) {
resolve('洗菜做饭 - 完成')
} else {
reject('洗菜做饭 - 出错')
}
}
function step2 (resolve, reject) {
console.log('2. 开始 - 坐下吃饭')
if (state == 1) {
resolve('坐下吃饭-完成')
} else {
reject('坐下吃饭-出错')
}
}
function step3 (resolve, reject) {
console.log('3. 开始 - 收拾桌子洗碗')
if (state == 1) {
resolve('收拾桌子洗碗-完成')
} else {
reject('收拾桌子洗碗-出错')
}
}
new Promise(step1).then(val => {
console.log(val)
return new Promise(step2)
}).then(val => {
console.log(val)
return new Promise(step3)
}).then(val => {
console.log(val)
return val
})
// 按照顺序输出以下
// 1. 开始 - 洗菜做饭
// 洗菜做饭 - 完成
// 2. 开始 - 坐下吃饭
// 坐下吃饭-完成
// 3. 开始 - 收拾桌子洗碗
// 收拾桌子洗碗-完成
16. class
类的使用
ES5
中经常使用方法或者对象去模拟 类 的使用,虽然可以实现功能。但是代码并不优雅,ES6
提供了 类 的使用。但是写 类 的时候要和ES5
中的对象和构造函数要区分开来。
1). 类的声明
class coder {
name (val) {
console.log(val)
}
}
上面的代码声明了一个最简单的coder
类。类里只有一个name
方法,方法打印出传递的参数
2). 类的使用
class Coder {
name (val) {
console.log(val)
}
}
let c = new Coder
c.name('john') // john
3). 类的多方法声明
class Coder {
name(val) {
console.log(val)
return val
}
age(val) {
console.log(this.name('john') + ':' + 'age' + val)
}
}
let c = new Coder
c.name('john1')
c.age(18)
4). 类的传参
类的参数传递可以使用constructor()
,传递参数后可以直接使用this.xxx
来使用
class Coder{
name (val) {
console.log(val)
return val
}
age (val) {
console.log(this.name('john') + ':' + 'age: ' + val)
}
constructor(a, b) {
this.a = a
this.b = b
}
add () {
return this.a + this.b
}
}
let c = new Coder(1, 2)
console.log(c.add()) // 3
上述代码使用constructor
来约定了传递了参数,然后将它用作add方法中使用把参数相加。
5). 类的继承
class Htmler extends Coder {
name (val) {
console.log(val)
return val
}
}
let h = new htmler
p.name('john')
17. 模块化操作
ES5
中进行模块化操作的时候需要引入第三方类库,ES6
新增了模块化操作,主要分为两个方面:
export
:负责模块的输出import
:负责引入模块
1). export
的用法
export
可以把变量,函数,对象进行模块化,提供外部调用接口,让外部进行引用。如下代码,新建一个temp.js
文件,然后在文件中输出一个模块变量。
// temp.js
export var a = 'john'
然后在目录下任意.js
文件中引入。以下为:index.js
文件
// index.js
import { temp } from './temp.js'
console.log(temp)
以上就是最简单的模块的输出和输入了
2). 多变量的输出
下面展示如何进行多变量的输出,只需要包装成对象就好了
// temp.js
var a = 'a'
var b = 'b'
var c = 'c'
export {a, b, c}
3). 函数的模块化输出
// temp.js
export function add(a, b) {
return a + b
}
4). as
的用法
有时候不想暴露模块里面的变量名称,需要给模块起一个更语义化的名称,这时候就可以用as
来操作。
// temp.js
var a = 'a'
var b = 'b'
var c = 'c'
export {
x as z,
y as b,
z as c
}
5). export default
的使用
加上default
相当于是一个默认的入口,在一个文件里export default
只能有一个。下面对比一下export
和export default
的区别
export
// temp.js
export var a = 'john'
export function add(a, b) {
return a + b
}
对应的引入方式如下:
// index.js
import {a, add} from './temp.js'
export default
// temp.js
export default var a = 'john'
对应的引入方式
// index.js
import temp from './temp.js'
ES6
的模块化不能直接在浏览器中预览,必须要使用Babel
进行编译后才能正常看到效果。