前端学习第十七天——ES6之Promise与Class类
Promise
异步操作的一种解决方案,Promise 一般用来解决层层嵌套的回调函数(回调地狱 callback hell)的问题
实例化构造函数生成实例对象
const p = new Promise(() => {});
Promise
的状态
const p = new Promise((resolve, reject) => {
// Promise 有 3 种状态,一开始是 pending(未完成),执行 resolve,变成 fulfilled(resolved),已成功
// 执行 reject,变成 rejected,已失败
// Promise 的状态一旦变化,就不会再改变了
// pending->fulfilled
// resolve();
// pending->rejected
// reject();
});
then
方法
pending->fulfilled 时,执行 then 的第一个回调函数
pending->rejected 时,执行 then 的第二个回调函数
p.then(
() => {
console.log('success');
},
() => {
console.log('error');
}
);
then
方法执行后返回一个新的Promise
对象
then
方法返回的Promise
对象的状态改变
const p = new Promise((resolve, reject) => {
// resolve();
reject();
});
p.then(
() => {
// console.log('success');
},
() => {
console.log('err');
// 在 then 的回调函数中,return 后面的东西,会用 Promise 包装一下
// return undefined;等价于
// return new Promise(resolve => {
// resolve(undefined);
// });
// 默认返回的永远都是成功状态的 Promise 对象
return new Promise((resolve, reject) => {
reject('reason');
});
}
)
.then(
data => {
console.log('success2', data);
// return undefined;
return new Promise(resolve => {
resolve(undefined);
});
},
err => {
console.log('err2', err);
}
)
.then(
data => {
console.log('success3', data);
},
err => {
console.log('err3', err);
}
);
catch
方法
catch
方法专门用来处理rejected
状态
catch
方法本质上是then
的特例
new Promise((resolve, reject) => {
reject('reason');
})
.then(data => {
console.log(data);
})
.catch(err => {
console.log(err);
throw new Error('reason');
})
.then(data => {
console.log(data);
})
.catch(err => {
console.log(err);
});
catch()
可以捕获它前面的错误
一般总是建议,Promise
对象后面要跟catch
方法,这样可以处理Promise
内部发生的错误。
3. finally
方法
当Promise
状态发生变化时,不论如何变化都会执行,不变化不执行。
finally()
本质上是then()
的特例
new Promise((resolve, reject) => {
// resolve(123);
reject('reason');
})
.finally(data => {
console.log(data);
})
.catch(err => {});
resolve()
方法
是成功状态Promise
的一种简写形式
new Promise(resolve => resolve('foo'));
// 简写
Promise.resolve('foo');
一般参数
Promise.resolve('foo').then(data => {
console.log(data);
});
当Promise.resolve()
接收的是Promise
对象时,直接返回这个Promise
对象,什么都不做
当resolve
函数接收的是Promise
对象时,后面的 then 会根据传递的Promise
对象的状态变化决定执行哪一个回调
reject()
方法
失败状态Promise
的一种简写形式
new Promise((resolve, reject) => {
reject('reason');
});
// 等价于
Promise.reject('reason');
不管什么参数,都会原封不动地向后传递,作为后续方法的参数
6. all()
方法
Promise.all()
关注多个Promise
对象的状态变化。传入多个Promise
实例,包装成一个新的 Promise
实例返回。
Promise.all()
的状态变化与所有传入的Promise
实例对象状态有关
所有状态都变成resolved
,最终的状态才会变成resolved
。
只要有一个变成rejected
,最终的状态就变成rejected
。
race
方法
Promise.race()
的状态取决于第一个完成的Promise
实例对象,如果第一个完成的成功了,那最终的就成功;如果第一个完成的失败了,那最终的就失败。allSettled
方法
Promise.allSettled()
的状态与传入的Promise 状态无关永远都是成功的它只会忠实的记录下各个Promise
的表现
注意事项
resolve
或reject
函数执行后的代码
推荐在调用resolve
或reject
函数的时候加上return,不再执行它们后面的代码。Promise.all
/race
/allSettled
的参数问题
参数如果不是Promise
数组,会将不是Promise
的数组元素转变成Promise
对象。
不只是数组,任何可遍历的都可以作为参数。数组、字符串、Set、Map、NodeList、arguments
3.Promise.all
/race
/allSettled
的错误处理
错误既可以单独处理,也可以统一处理
一旦被处理,就不会在其他地方再处理一遍
Class
类可以看做是对象的模板,用一个类可以创建出许多不同的对象
Class
的基本用法
类名一般大写
class Person {
// constructor 实例化时执行构造方法,所以必须有构造方法,但可以不写出来
constructor(name, age) {
// this 代表实例对象,上面定义的是实例属性/方法
this.name = name;
this.age = age;
// 一般在构造方法中定义属性,方法不在构造方法中定义
}
// 各实例共享的方法
speak() {
console.log('speak');
}
}
-
Class
的两种形式- 声明形式
class Person { constructor() {} speak() {} }
- 表达式形式
const Person = class { constructor() { console.log('constructor'); } } new Person();
立即执行匿名对象
new (class { constructor() { console.log('constructor'); } })();
实例属性
class Person {
age = 0;
sex = 'male';
getSex = function () {
return this.sex;
};
}
静态属性
类的方法
class Person {
constructor(name) {
this.name = name;
}
static speak() {
console.log('人类可以说话');
// this 指向类
console.log(this);
}
}
静态属性
类的属性
class Person {
constructor(name) {
this.name = name;
}
// 不要这么写,目前只是提案,有兼容性问题
// static version = '1.0';
// 写成方法的形式
static getVersion() {
return '1.0';
}
}
// 定义静态属性,也不推荐,违背了封装性的原则
Person.version = '1.0';
私有属性
声明的属性只能和方法,只能在类里使用。
一般情况下,类的属性和方法都是公开的,公有的属性和方法可以被外界修改,造成意想不到的错误。
模拟私有属性和方法
- _ 开头表示私有
class Person {
constructor(name) {
this._name = name;
}
}
- 将私有属性和方法移出类
(function () {
// 移出类
let name = '';
class Person {
constructor(username) {
name = username;
}
speak() {
console.log('speak');
}
getName() {
return name;
}
}
window.Person = Person;
})();
(function () {
const p = new Person('zgbx');
console.log(p.name);
console.log(p.getName());
})();
extends
class Person {
constructor(name, sex) {
this.name = name;
this.sex = sex;
this.say = function () {
console.log('say');
};
}
speak() {
console.log('speak');
}
static speak() {
console.log('static speak');
}
}
Person.version = '1.0';
class Programmer extends Person {
constructor(name, sex) {
// 继承父类的构造方法
super(name, sex);
}
}
改写继承的属性或方法
class Programmer extends Person {
constructor(name, sex, feature) {
// this 操作不能放在 super 前面
super(name, sex);
this.feature = feature;
}
// 添加自己的方法
hi() {
console.log('hi');
}
// 同名覆盖
speak() {
console.log('Programmer speak');
}
}
super
- 作为函数调用
代表父类的构造方法,只能用在子类的构造方法中,用在其他地方就会报错
super
虽然代表了父类的构造方法,但是内部的this
指向子类的实例 - 作为对象使用
- 在构造方法中使用或一般方法中使用
super
代表父类的原型对象Person.prototype
,所以定义在父类实例上的方法或属性,是无法通过super
调用的。通过super
调用父类的方法时,方法内部的this指向当前的子类实例 - 在静态方法中使用
指向父类,而不是父类的原型对象。通过super
调用父类的方法时,方法内部的 this 指向当前的子类,而不是子类的实例
- 在构造方法中使用或一般方法中使用
- 注意事项
使用super
的时候,必须显式指定是作为函数还是作为对象使用,否则会报错