JavaScript ES6语法学习笔记 04、Promise与Class(下)

举报
长路 发表于 2022/11/28 21:34:13 2022/11/28
【摘要】 文章目录前言一、Promise1.1、介绍Promise(认识异步)1.2、Promise的基本使用1.2.1、认识Promise的三个状态1.2.2、Promise中回调函数原理(参数为函数缘由)1.2.3、Promise的then()方法解决实际问题:回调地狱(解决过多函数回调相互嵌套问题)1.3、Promise对象的catch()方法1.3.1、替换then()中的第二个回调函数1.3.2、

二、Class类

2.1、Class的基本使用

2.1.1、构造函数

ES6之前,我们是通过new构造函数来创建的指定对象,为了更好的区分类与函数,ES6推出了类相关的关键字如class

重要几点内容

  1. class表示声明一个类,其底层实际上就是一个函数
  2. 定义了一个class后,默认会自带一个无参构造器,若是自定义构造函数(使用constructor),就会覆盖掉默认的无参构造函数,之后使用new都会走该构造函数。
  3. 在构造函数中使用this.属性是为对应生成的对象添加的实例属性,而不是该类自带的属性。

构造函数示例

<script>
    class Person {
        //默认自带了一个无参的构造函数
        //下面是自定义的构造函数
        constructor(name, sex) {
            this.name = name;
            this.sex = sex;
        }
    }
    //查看一下Person类状态
    console.log(Person);
    //Person的本质:就是一个函数
    console.log(typeof Person);;
    //构造函数
    console.log(new Person());;
    console.log(new Person('changlu', '男'));;
</script>

image-20210624180231869



2.1.2、函数定义(两种情况)

构造函数中使用this.函数形式(不推荐,每次创建实例时对应的speak函数都会指向不同的内存地址,造成内存浪费)

<script>
    class Person {
        constructor() {
            this.speak = () => { console.log("hello"); }
        }
    }

    //创建的多个实例都是引用的一个函数
    console.log(new Person().speak === new Person().speak);
    console.log(Person);
</script>

image-20210624181606898


类中义定义函数(推荐,本质在对象原型链中添加函数)

<script>
    class Person {
        //类中创建函数
        speak() {
            console.log("Person类的speak()方法.....");
        }
    }

    //创建的多个实例都是引用的一个函数
    console.log(new Person().speak === new Person().speak);
    console.log(Person);
</script>

image-20210624181151510

  • speak()函数方法被添加到了Person的原型对象中去了。这实际上与之前执行Person.prototype.speak = ()=>{};效果一致。


2.2.2、Class的两种定义形式(声明与表达形式)

声明形式

<script>
    //声明形式
    class Person {
        constructor() { }
    }

    console.log(new Person());
</script>

image-20210624182612170

表达式形式

实际与快速执行函数基本类似,如下:能够快速定义类并且创建类实例

<script>
    //表达式形式
    console.log(
        //new (class xxx{})()
        new (class Person {
            constructor() { }
        })()
    );
</script>

image-20210624182612170



2.2、class中的实例属性

认识class类中的实例属性

什么是实例属性呢

  • 之前我们在构造器中使用this.属性进行赋值实际上就是给生成的对象创建并赋值属性,这里的实例属性也是指的这个效果。
<script>
    class Person {
        //实例属性:不能使用任何关键字来进行定义如let、var、const等等
        //本质就是会执行this.name='xxx';this.age=0;
        name = 'xxx';
   		age = 0;
    }
    //查看下这个Person类:在该类中并没有实例属性!
    console.log(Person);
    //创建好实例后就会得到对应的实例属性
    console.log(new Person().name)
    console.log(new Person().age)
</script>

image-20210624184133681

结论:直接在类中创建的属性就是实例属性!


构造器中如何赋值实例属性

<script>
    class Person {
        //实例属性   本质就是会执行this.name='xxx';this.age=0;
        name = 'xxx';
        age = 0;
        constructor(name, age, sex) {
            //根据参数传递情况来是否对实例属性进行赋值
            if (sex !== undefined) {
                this.name = name;
                this.age = age;
                this.sex = sex;
            } else if (age !== undefined) {
                this.name = name;
                this.age = age;
            }

        }
    }
    console.log(new Person());
    console.log(new Person('changlu', 18, '男'));
</script>

image-20210624185039833



2.3、静态方法与静态属性

2.3.1、静态方法与静态属性的基本定义

静态方法

定义位置与方式:直接在类中定义static 开头的函数名即可。

本质:就是在下面Perosn构造函数上添加了一个方法,不会出现在原型链中!

  • 相当于之前执行Person.xxx = ()=>{},直接添加在构造函数上!

示例

<script>
    class Person {
        //静态方法:添加到Person构造函数上去的
        static speak() {
            console.log("i am Person!")
        }
    }
    console.log(Person);
    //实例化对象的原型链中没有对应静态方法
    console.log(new Person());
    new Person().speak();//报异常,没有对应定义
</script>

image-20210624185623152


静态属性

定义的方式很简单:直接在类中对属性添加static即可。

说明:静态属性只有在类中有,实例中没有!

class Person {
    static num = 1;
    static str = "hello";
}

console.log(Person);
console.log(Person.num);
console.log(Person.str);

image-20210624190101411



2.3.2、this对象介绍(静态方法、构造函数与普通函数)

静态方法中的this

结论:静态方法中的this指向的是类。

<script>
    class Person {
        static num = 1;
    //静态方法:添加到Person构造函数上去的
    static speak() {
        console.log("i am Person!")
        console.log('静态方法中的this对象为:', this);
        //能够访问到Person类中的值
        console.log(this.num);
    }
    }
    //调用静态方法
    Person.speak();
</script>

image-20210624190432242


普通方法与构造函数中的this

结论:普通方法与构造函数中的this都指向了对应创建与调用的对象实例!

<script>
    class Person {
        constructor() {
            console.log(`constructor中的this为:${this}`)
        }

        speak() {
            console.log(`普通函数中的this为:${this}`)
        }
    }
    //结论:原型对象链中的函数以及构造函数中的this指向了对应创建与调用的实例
    new Person().speak();//执行了构造函数以及调用了函数
</script>

image-20210624190833588



2.4、私有属性与方法

问题说明:对于类中你定义静态方法或者实例方法、属性,在外部浏览器都很容易受到篡改等危险操作,那么我们就需要来定义私有属性与方法来进行防范!

有两种方式来进行定义私有属性

  1. 模拟私有属性与方法:通过在变量名开头添加_来俗成约定表示私有属性或方法。(此方法仅仅只是约定,并没有进行了约束!)
  2. 将私有属性与方法移除类:需要搭配立即调用函数表达式()()来进行移出私有属性或方法!

方式一:模拟私有属性与方法,该方式还是不太可靠的

<script>
    class Person {
        constructor(name, age) {
            this._name = name;
            this._age = age;
        }

        //通过普通函数来获得
        getName() {
            return this._name;
        }

        getAge() {
            return this._age;
        }
    }
    //创建一个实例
    const p = new Person('changlu', 18)
    console.log(p);
    console.log(p.getName());
    console.log(p.getAge());
</script>

image-20210624191623752


方式二:将属性移出类,配合立即调用函数表达式

<script>
    (function () {
        //将指定的属性移到外面去
        let name = '';
        let pw = '';

        class Person {
            constructor(username, password) {
                //定义的私有属性必须与传入的形参名称不同,否则无法识别
                name = username;
                pw = password;
            }
			
            //获取属性并不是从自己本身对象中获取的,而是通过该作用域来得到!
            getUsername() {
                return name;
            }

            getPassword() {
                return pw;
            }
        }

        //绑定到window上
        window.Person = Person;
    })();

    //通过()()形式,创建多个实例也是可以的,会形成多个局部作用域
    //创建第一个实例,只能够通过调用方法才能够获取到对应的值
    console.log("第一个实例:");
    const p = new Person("changlu", '123456')
    console.log(p);
    console.log(p.getUsername());
    console.log(p.getPassword());
    //想要尝试直接获取是不允许的!!!
    console.log(p.name);
    console.log(p.pw);

    //创建第二个实例,只能够通过调用方法才能够获取到对应的值
    console.log("第二个实例:");
    const p1 = new Person("liner", '987654')
    console.log(p1);
    console.log(p1.getUsername());
    console.log(p1.getPassword());
    //想要尝试直接获取是不允许的!!!
    console.log(p1.name);
    console.log(p1.pw);

</script>

image-20210624192607800



2.5、extends继承

2.5.1、初识extends继承(三个结论)

结论

  1. 子类的类原型对象指向着父类的类原型对象,意味通过子类的类就能够调用执行父类的静态方法
  2. 子类的实例原型对象指向着父类的实例原型对象,意味着子类的实例能够调用执行父类实例的普通方法
  3. 子类能够具有父类的实例属性

示例

<script>
    class Person {
        //实例变量
        num = 1;
    //静态变量
    st_num = 2;

    //静态方法
    static st_speak() {
        console.log("st_speak()");
    }

    //实例方法
    speak() {
        console.log("speak()");
    }
    }

    //自定义类继承Person类
    class Student extends Person {

    }

    //查看Studnent类的结构
    console.log(Student);
    const p = new Student();
    //查看Student进行new的实例
    console.log(p);
    //调用Student实例的speak()方法
    p.speak();
</script>

image-20210624194114313



2.5.2、继承后子类调用父类普通方法或构造函数中的的this

结论

  1. new 子类时,会首先去调用父类的构造函数,紧接着调用子类的构造函数。其中的this在父类构造器中指向的就是父类实例对象,在子类构造中就是指向子类实例对象
  2. 子类调用父类中的普通方法时,该方法其中的this指向子类对象实例

结论一证明

<script>
    class Person {
        name = 'Person';
    constructor() {
        console.log(this, this.name);
    }
    }

    //自定义类继承Person类
    class Student extends Person {
        name = 'Student';
    constructor() {
        super();//若是不写会报错(原因是父类的无参构造是自定义的),此时会多执行一次父类的默认的构造函数
        console.log(this, this.name);
    }
    }

    const p = new Student();
    //查看Student进行new的实例
    console.log(p);
</script>

image-20210624195124966


结论二证明

<script>
    class Person {
        name = "Person";
    info() {
        //普通方法函数中,子类执行调用的函数this就是指向子类实例
        console.log(this, this.name);
    }
    }

    //自定义类继承Person类
    class Student extends Person {
        name = 'Student';
    }

    new Student().info();
</script>

image-20210624195506893



2.5.3、重写(覆盖)父类的属性与方法

仅仅只需要在子类中声明定义父类的属性与方法即可,这里就不进行演示了!



2.6、super用途(对象、函数)

2.6.1、作为函数调用

super():作为函数时,只能够使用于子类的构造函数中,用在其他地方就会报错!

重点:super虽然代表了父类的构造方法,但是内部的this指向子类的实例(暂时还是持怀疑的!!!)。

示例

<script>
    class Person {
        constructor(name, age) {
            this.name = name;
            this.age = age;
            console.log(this);

        }
    }

    //自定义类继承Person类
    class Student extends Person {
        constructor(name, age, sex) {
            super(name, age);
            this.sex = sex;
        }
    }

    console.log(new Student('changlu', 18, '男'));
</script>

image-20210624200327188



2.6.2、作为对象使用

super.属性:在构造方法中或一般方法中使用,super代表父类的原型对象,通过super调用父类的方法时,方法内部的this依旧指向当前的子类实例。

注意:定义在父类实例上的方法与属性是无法通过super调用得到的,但是方法是可以执行的!

<script>
    class Person {
        name = "Person";
    getName() {
        console.log(this);//子类调用时指向子类实例
        return this.name;
    }
    }

    //自定义类继承Person类
    class Student extends Person {
        name = "Student";
    //证明父类中的方法里使用的this是子类的对象
    getName() {
        return super.getName();
    }
    }

    console.log(new Student().getName());
</script>

image-20210624201335304



注意事项

1、在子类构造器中使用super前需要先执行super()

2、在使用super的时候,必须显示是作为函数super(),还是作为对象使用,否则会报错(如仅仅是是输出super)!



整理者:长路 时间:2021.6.23

Student’;
}

new Student().info();
</script> ```

[外链图片转存中…(img-mFVe8OFz-1651988840423)]



2.5.3、重写(覆盖)父类的属性与方法

仅仅只需要在子类中声明定义父类的属性与方法即可,这里就不进行演示了!



2.6、super用途(对象、函数)

2.6.1、作为函数调用

super():作为函数时,只能够使用于子类的构造函数中,用在其他地方就会报错!

重点:super虽然代表了父类的构造方法,但是内部的this指向子类的实例(暂时还是持怀疑的!!!)。

示例

<script>
    class Person {
        constructor(name, age) {
            this.name = name;
            this.age = age;
            console.log(this);

        }
    }

    //自定义类继承Person类
    class Student extends Person {
        constructor(name, age, sex) {
            super(name, age);
            this.sex = sex;
        }
    }

    console.log(new Student('changlu', 18, '男'));
</script>

[外链图片转存中…(img-X9zPtbiw-1651988840423)]



2.6.2、作为对象使用

super.属性:在构造方法中或一般方法中使用,super代表父类的原型对象,通过super调用父类的方法时,方法内部的this依旧指向当前的子类实例。

注意:定义在父类实例上的方法与属性是无法通过super调用得到的,但是方法是可以执行的!

<script>
    class Person {
        name = "Person";
    getName() {
        console.log(this);//子类调用时指向子类实例
        return this.name;
    }
    }

    //自定义类继承Person类
    class Student extends Person {
        name = "Student";
    //证明父类中的方法里使用的this是子类的对象
    getName() {
        return super.getName();
    }
    }

    console.log(new Student().getName());
</script>

[外链图片转存中…(img-evCEq4md-1651988840423)]



注意事项

1、在子类构造器中使用super前需要先执行super()

2、在使用super的时候,必须显示是作为函数super(),还是作为对象使用,否则会报错(如仅仅是是输出super)!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。