ES6 之 Promise 与 Class 类

初始Promise

认识 Promise
Promise 是异步操作的一种解决方案。

什么时候使用Promise
Promise一般用来解决层层嵌套的回调函数(回调地狱 callback hell)的问题

Promise 基本用法

实例化构造函数生成的实例对象
第一步:先实例化对象,然后后边加一个回调函数,回调函数内有两个形参;
语法:实例化构造函数内有一个回调函数

const p = new Promise((resolve, reject) => {
            resolve({usernme:'Alex'})
        })    // p 就是我们需要的 实例化对象

Promise 的状态 即是形参又是Promise内的函数
一开始是从:pending 等待状态;
执行resolve函数后:变成 fulfilled 满足状态;
或者是执行reject函数:变成 rejected 拒绝状态;

Promise 的状态一旦完成变化,就不会再改变了

resolve 和 reject 函数的参数
这两个函数是 可以传参给后面相对应的than()中的回调函数当作实参,需要设置形参来接收。

const p = new Promise((resolve, reject) => {
            reject(new Error('reason'))
        })

        p.then(()=>{
            console.log('success');
        },(err)=>{
            console.log('error',err);
        })

以下是3个 实例对象的方法:

then () 方法 ——非常重要

给实例对象 p 调用方法then,方法里有两个回调函数。

p.then(()=>{},()=>{})      // 里面有两个回调
  1. 什么时候执行?
    pending -> fulfilled 时,执行then的第一个回调函数;
    pending -> rejected时,执行then的第二个回调函数;
    状态不改变,then() 的回调函数都不会被执行

  2. 执行后的返回值
    then方法执行后返回一个新的Promise对象,可以继续接着then或catch,且then()是可以用return向后传值

const p = new Promise((resolve,reject)=>{
            resolve()
        })
        
const p2 = p.then(
      ()=>{},
      ()=>{}
      ).then()
  1. then 方法返回的Promise对象的状态改变
    用then方法返回的Promise对象的状态来改变下一个then方法的回调:
    规则:在 then 的回调函数中,return后面的东西,会用Promise包装一下;
    比如:return undefined;
    等价于 返回了一个新的Promise对象,并默认用resolve ( ) 满意状态包装一下返回值
return new Promise((resolve,reject)=>{
                resolve(undefined)
            })

默认返回的永远都是成功状态的Promise对象。

示例:

const p = new Promise((resolve,reject)=>{
            reject()
        })
        
        const p2 = p.then(
            ()=>{},
            ()=>{
                return 123;
            }
            ).then(
            (date)=>{
                console.log(date);
            },
            ()=>{}   
            )

如果要返回的拒绝状态那就设置返回一个完整Promise构成函数,调用reject() 函数即可

return new Promise((resolve,reject)=>{
            reject('reason');
        })

实际开发中,一般用then的满足状态,只写一个回调函数

catch () 方法 —— 非常重要

专门用来捕获 rejected 状态的,catch本质上就是then的一个特例。
一般总是建议,Promise 对象后面要跟catch方法,这样可以处理Promise内部发生的错误。

new Promise ((resolve,reject)=>{
            reject('jhgkjh')
        })
        .catch(err =>{
            console.log(err);
        })
        

finally ()
当Promise状态发生变化时,不论如何变化都会执行。

Promise 的构造函数方法

  1. Promise.resolve ()方法
    是成功状态Promise的一种简写形式

参数:一般参数

Promise.resolve('foo').then(data => {console.log(data);})

参数:Promise对象
当Promise.resolve()接收的是Promise对象时,直接返回这个Promise对象,什么都不做

const p1 = new Promise (resolve =>{
            setTimeout(resolve,1000,'我执行了')
        })
        
        Promise.resolve(p1).then(data =>{
            console.log(data);
        })
        
        Promise.resolve(p1)===p1

传入对象的状态接管后面then的控制权,后面then会根据传递的Promise对象的状态变化决定执行哪一个回调

const p1 = new Promise (resolve =>{
            setTimeout(resolve,1000,'我执行了')
        })
        
        new Promise (resovle => resovle(p1)).then(data =>{
        console.log(data);    
        })
  1. Promise.reject () 方法
    是拒绝状态Promise的一种简写形式
Promise.reject('reason')

参数:
不管什么参数,都会原封不动地向后传递,作为后续方法的参数

Promise.all ()—— 非常重要

有什么用?
Promise.all() 关注多个Promise对象的状态变化
可以传入多个Promise实例,包装成一个新的Promise实例返回

  1. 基本用法
    Promise.all() 的状态变化与所有传入的Promise实例对象状态有关
    所有状态都成resolve,最终的状态才会变成rosolved
    只要有一个变成rejected,最终的状态就变成rejected
const delay = ms => {
            return new Promise(resolve => {
                setTimeout(resolve, ms)
            })
        }

        const p1 = delay(1000).then(data => {
            console.log('p1来了');
            return 'p1'
        })

        const p2 = delay(2000).then(data => {
            console.log('p2来了');
            return 'p2'
        })

        const p = Promise.all([p1, p2]);
        p.then(
            (date) => {
                console.log(date); 
            },
            (err) => {
                console.log(err);
            },
        )
const delay = ms => {
            return new Promise(resolve => {
                setTimeout(resolve, ms)
            })
        }

        const p1 = delay(1000).then(data => {
            console.log('p1来了');
            return 'p1'
        })

        const p2 = delay(2000).then(data => {
            console.log('p2来了');
            return Promise.reject('sfsf')
        })

        const p = Promise.all([p1, p2]);
        p.then(
            (date) => {
                console.log(date);
            },
            (err) => {
                console.log(err);

Promise.race () 方法

基本用法
Promise.race() 的状态取决于第一个完成的Promise实例对象,
如果第一个完成的成功了,那最终的就成功;如果第一个完成的失败了,那最终的就失败

const delay = ms => {
            return new Promise(resolve => {
                setTimeout(resolve, ms)
            })
        }

        const p1 = delay(1000).then(data => {
            console.log('p1来了');
            return Promise.reject('第一个实例对象来决定状态')
        })

        const p2 = delay(2000).then(data => {
            console.log('p2来了');
            return 'p2'
        })

        const racePromise=Promise.race([p1,p2])
        racePromise.then(
            (data)=>{
                console.log(data);
            },
            (err)=>{
                console.log(err);
            }
        )

Promise.allSettled () 方法

基本用法:
Promise.allSettled() 的状态与传入的Promise状态无关
永远都是成功的
它只会忠实的记录下各个Promise的表现

Promise 的注意事项

resolve 或 reject 执行后的代码
实际上还可以可以执行后面的代码语句,但还是
推荐在调用resovle 或 reject函数的时候加上return,不再执行它们后面的代码。

Promise.all/race/allSettled的参数问题
参数如果不是Promise数组,会将不是Promise的数组转变成Promise 对象

Promise.all([1,2,3]).then(datas =>{
            console.log(datas);
        })

不只是数组,任何可遍历的都可以作为参数

Promise.all(new Set([1,2,3])).then(datas =>{
            console.log(datas);
        })

Promise.all/race/allSettled的错误处理

错误既可以单独处理,也可以统一处理
一旦被处理,就不会在其他地方再处理一遍

Promise 的应用

异步加载图片

const loadimgAsync = url =>{
// Promise内不需要写太多的语句,只须写明什么情况一下调用resolve()函数,什么情况下调用reject()函数即可,具体的语句要在then()方法里来写
            return new Promise((resolve,reject)=>{
                // 实例化一个图像构成函数
                const img = new Image();
                
                // 成功加载的时候
                img.onload = ()=>{
                    resolve(img);
                } 
				//加载错误时
                img.onerror = ()=>{
                    reject(new Error(`Could not load image at ${url}`));
                } 
                // 把实参传给对象的src属性
                img.src = url;

            })
        };
        const myImg = document.querySelector('img');

        loadimgAsync('https://pic4.zhimg.com/80/v2-60cebf105e36cb2983964c95960ec75b_1440w.webp')
        .then(img=>{
            // console.log(img.src);
            setTimeout(()=>{
                myImg.src = img.src
            },2000)
        }
        // 还要写错误的情况下捕获语法
        ).catch(error=>{
            console.log(error);
        })

Class 类

认识Class

类可以看做是对象的模版,用一个类可以创建出许多不同的对象

Class的基本用法

所有的类都必须有构造方法
实例化时执行构造方法,但可以不写出来

class Person{
            constructor(name,age){
                this.name=name;
                this.age=age;
                this.speak=()=>{
                    // 一般在构造方法中定义属性,方法不在构造方法中定义
                }
            }
            // 各实例共享的方法
            speak(){}
        }

        const p = new Person('zs',18);
        const ls = new Person('ss',28);
        console.log(ls.name);
        console.log(p.age);
        console.log(ls.speak());

Class 与构造函数

本质相同,都是函数
Class类更加简单直观

class Person {
            constructor(name, age) {
                this.name = name;
                this.age = age;
            }

            // 各实例共享的方法
            speak() { }
        }

Class的两种定义形式

声明形式

class Person {
            constructor(){}

            speak(){}
        }

表达式形式

const Person = class{
            constructor(){
                console.log('constuctor');
            }

            speak(){}
        }
        new Person()

匿名类 (立即执行的类)

new (class{
            constructor(){
                console.log('sfsf');
            }
        })();

实例属性、静态方法和静态属性

1.实例属性

class Person{
            // 可以直接例出 实例属性的默认值; 与构造方法平行
            age =0;
            sex = 'male'
            constructor(age, sex){
                // 构造方法里的属性必须加this. 才知道给实例对象添加属性
                // this指向的是实例对象
                this.age = 18;
                this.sex = sex;
            }

        }
        const p=new Person(20,'Alex');
        console.log(p.age);
  1. 静态方法
    也就是类的方法,先在方法前用static声明 ,然后直接用类来调用
class Person{
          static speak(){
                console.log('人类可以说话');
                // 这里的this指向的是类
            }
        }
        
        Person.speak()
  1. 静态属性(选学)
    也就是类的属性 用类的方法来写, return 值即可

私有属性和方法

为什么需要私有属性和方法
一般情况下,类的属性和方法都是公开的
公有的属性和方法可以被外界修改,造成风险

  1. 模拟私有属性和方法
    _ 开头表示私有
constructor(name, age) {
                this._name = name;
                this._age = age;
                this.say = function () {
                    
                }

            }

将私有属性和方法移出类
这是第二种方法
都放在匿名函数中,使外部不能直接访问到它

(function () {
            let name = '';
            class Person {
                constructor(username) {
                    // this.name = name;
                    name=username
                }
                speak() {
                    console.log('speak');
                }

                getName(){
                    return name
                }

            }
            // 暴露出来
            window.Person=Person
        })()
        
        const p = new Person('Alex');
        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 peaek');
            }
        }
	//类的属性
        Person.version = '1.0';


        class Programmer extends Person{
            constructor(name,sex){
                super(name,sex)
            }
        }
        const zs=new Programmer('zs','男')

        console.log(zs.name);
        console.log(zs.sex);
        zs.say();
        zs.speak();
        Programmer.speak()
        console.log(Programmer.version);

改写继承的属性或方法
同名的会覆盖父类的属性

class Programmer extends Person{
            constructor(name,sex,feature){
                super(name,sex)
                //this要放在super后边,子类this添加独有属性
                this.feature = feature;
            }
		//同名覆盖
            speak(){
                console.log('Programmer speak');
            }
        }
        Programmer.version = '2.0'

super

1.作为函数调用
代表着父类的构造方法,只能用在子类的构造方法中
super虽然代表了父类的构造方法,但是内部的this指向仍是子类的实例

2.作为对象使用
2.1在构造方法中使用或一般方法使用
super代表父类的原型对象 Person.prototype,所以父类公共的方法是可以直接被super来调用的
但定义在父类实例上的方法或属性,是无法通过super对象来调用的
通过super调用父类的方法时,方法内部的this指向子类实例

class Person{
            constructor(name,sex){
                this.name=name;
                this.sex=sex;
	//构造方法里的属性和方法如果被子类继承,this指向子类的实例
                this.say = function(){
                    console.log('say');
                }
            }

            speak(){
                console.log('qo speak');
            }

            static speak(){
                console.log('static peaek');
            }
        }

        Person.version = '1.0';


        class Programmer extends Person{
            constructor(name,sex,feature){
            //作为函数,代表父类的构造方法,只能用在子类的构造方法中
                super(name,sex);
             //作为对象,super代表父类的原型对象 Person.prototype
                super.speak()

                this.feature = feature;
//在父类公共方法基础之上,加上独有的方法 
speak(){
	super.speak();
	console.log('doyou peaek');
}
		
            }

2.2 在静态方法中使用
super指向父类的静态方法,而不是作为父类的原型对象
通过super调用父类的静态方法时,方法内部的this指向当前子类

static speak(){
                super.speak();
                console.log('Programmer speak');
            }
            
        }
        Programmer.version = '2.0'

        const zs=new Programmer('zs','男','身休')

        
        Programmer.speak()

3.注意事项
使用super的时候,必须显式指定是作为函数还是作为对象使用,否则会报错

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值