我们常说JS类是一种语法糖,那么也就是说在实现同样功能的时候,使用类比使用构造函数等其他方法实现同样的功能会好很多,本质上来说,类就是一种函数,某些情况下它可以当成函数来使用。即如果只是了解其用法,并没有很多新的东西需要我们用大量时间去学习。

我们知道,类可以理解为,将某一类对象所共有的一些属性和方法放在一个类里面,当我们需要调用其共有的属性和方法的时候,我们可以直接在类里面取就可以了,这可以提高代码的复用率,让自己的代码更优雅一点。

接下来会对比说明类在使用的时候会有什么不一样的地方,即它的优点又在哪里。

规范

1. 类是抽象了对象的公共部分,泛指某一大类。对象特指某一个,通过类实例化一个具体的对象。
2. 书写规范

- 通过class关键字创建类,类名定义成首字母大写
- 类里面的函数不需要写function
- 多个函数之间不需要用逗号分割

3. 在ES6中没有变量提升,所以必须先定义类,才能通过类实例化对象。

4. 函数声明和类声明之间的一个重要区别在于,函数声明会提升,类声明不会。下面一段代码就很好的说明了两者的区别。

<script>
//不会报错
 fn();
    function fn(){
        console.log(333);
    }
</script>


<!-- 变量提升 -->
<script>
    //报错
    let obj=new Father('李白',22);
    class Father{
        constructor(name,age){
            this.name=name;
            this.age=age;
        }
    }

5. 类里面共有的属性和方法一定要加this使用。

类必须使用new实例化对象

<button>按钮</button>
<script>
    class Father{
        constructor(name,age){
            this.name=name;
            this.age=age;
            //不加this会报错
            this.btn=document.querySelector('button');
            this.btn.onclick=this.sing;
        }
        sing(){
            console.log(3333);
            console.log(this);//指向button
        }
    }
    let obj=new Father('杜甫',22);
</script>

类表达式

1.. 类表达式也可以定义类。类表达式可以命名或不命名。命名类表达式的名称是该类体的局部名称。

<script>
       let p=class Father{
            constructor(name,age){
                this.name=name;
                this.age=age;
            }
            sing(){
                console.log(111);
            }
        }
        let obj1=new p();
        console.log(p.name);//Father
        // console.log(p.sing());//报错
        obj1.sing();//11
        

        let p1=class {
            constructor(name,age){
                this.name=name;
                this.age=age;
            }
            sing(){
                console.log(111);
            }
        }
        console.log(p1.name);//p1
         //console.log(p1.sing());//报错

    </script>

2. 如果想在类体内部也能引用这个类本身,那么你就可以使用命名类表达式,并且这个类名只能在类体内部访问。

<script>
        let s=class Father{
            sing(){
                return Father.name;
            }
        }
        let obj=new s();
        console.log(obj.sing());//Father
        console.log(s.name);//Father
        console.log(Father.name);//报错
    </script>

严格模式

1. 类声明和类表达式的主体都执行在严格模式下。
1)严格模式会将JavaScript陷阱直接变成明显的错误。
2)严格模式修正了一些引擎难以优化的错误。
3)同样的代码有些时候严格模式会比非严格模式下更快。
4)严格模式禁用了一些有可能在未来版本中定义的语法。

<script>
    // class Father{
    //     constructor(name,age){
    //         this.name=name;
    //         this.age=age;
    //     }
    //     sing(){
    //         t=new String();//报错
    //         console.log(this);
    //     }
    // }
    // let obj=new Father('王勃',33);
    // obj.sing();//Father {name: '王勃', age: 33}


    //不会报错
    function Fn(name){
        this.name=name;
       t=new String();
    }


</script>

使用 ‘use strict’; 可以进入严格模式。

constructor

1. constructor()方法是类的构造方法(默认),用于传递参数,返回实例对象。
通过new命令生成对象实例时,自动调用该方法。如果没有显示定义,类的内部会自动为我们创建一个constructor()方法。

<script>
    class Father{
        constructor(name,age){
            this.name=name;
            this.age=age;
            this.sing();
        }
        sing(){
            console.log(5555);
        }
    }
    let obj=new Father('李白',22);
    //控制台会打印555,一旦new,构造函数就会自动执行
    // obj.sing();//打印2次
</script>

2. constructor里面的this指向的是创建的实例对象。
3. 一个构造函数可以使用super关键字来调用一个父类的构造函数。

super

1. super关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数。
2. 就近原则

- 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的方法。
- 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法。

<script>
    class Father{
        sing(){
            console.log('唱歌');
        }
    }
    class Son extends Father{
        sing(){
            return super.sing();
        }
    }
    let obj=new Son();
    obj.sing();

3. 子类构造函数中使用super,必须放到this前面,即必须先调用构造方法,再使用子类的构造方法。

<script>
    class Father{
        constructor(name,age){
            this.name=name;
            this.age=age;
        }
        sing(){
            console.log('唱歌');
        }
    }
    class Son extends Father{
        // constructor(sex){
        //     this.sex;
        // }报错
        // constructor(sex){
        //     super(name,age);
        // }报错
        constructor(name,age,sex){
            super(name,age);
            this.sex=sex;
        }
        sing(){
            return super.sing();
        }
    }
    let obj=new Son();
    
</script>

static

1. static只能通过类来访问。即static只能通过类自身来调用,不能通过类的实例来调用。

<script>

     class Father{
        constructor(name,age){
            this.name=name;
            this.age=age;
        }
        sing(){
            console.log(this.name+'唱歌!');
        }
        static fb(){
            console.log(this.name);
        }
     }
     Father.song=function (){
        console.log(this.name);
     }

     Father.prototype.fa=function (){
        console.log(this.age);
     }

     console.log(typeof Father);//fucntion
     let obj1=new Father('李白',33);
     let obj2=new Father('杜甫',32);
     obj1.sing();
     obj2.sing();

     console.log(obj1.sing===obj2.sing);//true

     //obj1.song();//报错
     obj2.fa();//32
    //  obj1.fb();//报错
    Father.fb();//Father
     Father.song();//Father

    </script>

2. 静态方法调用同一个类中的其他静态方法,可使用 this 关键字。

3. 非静态方法中,不能直接使用 this 关键字来访问静态方法。而是要用类名来调用;或者用构造函数的属性来调用该方法。

<script>
        class Father{
            sing(){
               return this.fa();
            }报错
            // sing(){
            //    return Father.fa();
            // }
            static fa(){
                console.log(22);
            }
        }
        let obj=new Father();
        obj.sing();//22
    </script>

extends

1. extends 关键字在 类声明 或 类表达式 中用于创建一个类作为另一个类的一个子类.

2. 子类中定义了构造函数,那么它必须先调用 super() 才能使用 this。

继承前面已有简单说明,这里我们看一下构造函数里面是怎样实现继承的,通过下面代码会发现使用类实现继承要好很多。

<script>

    function Star(name,age){
        this.name=name;
        this.age=age;
    }
    Star.prototype.sing=function (){
        console.log('唱歌');
    }
    function Son(name,age,sex){
        Star.call(this,name,age);
        this.sex=sex;
    }
    //属性的继承
    let obj1=new Son('杜甫',22,'男');
    console.log(obj1);

    //方法的继承
    Son.prototype=new Star();
    let obj=new Son('李白',52,'男');
    console.log(obj);

    obj.sing();

    </script>