【JS核心概念】Class的基本语法

一、简单使用

    // 定义一个Animal类
    class Animal {
        // 构造方法,相当于ES5中的构造函数
        // this代表的是实例对象
        constructor(kind) {
            this.kind = kind;
        }
        getKind() {
            console.log(this.kind);
        }
    }
  • 类必须使用new运算符调用,直接调用会报错
    // 类必须使用new运算符来调用,如果直接调用会报错,这点跟ES5的构造函数不一样
    const cat = new Animal('cat');
    // const cat = Animal('cat'); // TypeError: Class constructor Animal cannot be invoked without 'new'
    cat.getKind(); // cat
  • 类的数据类型是函数,类本身就指向构造函数
    console.log(typeof Animal); // function
    console.log(Animal === Animal.prototype.constructor); // true
  • 类中的所有方法都是定义在类的prototype属性上的
  • 实例的属性除非显式的定义在其本身(即this对象上),否则都是定义在原型上
    // kind为实例属性
    console.log(Object.getOwnPropertyNames(cat)); // [ 'kind' ]
    // constructor、getKind为原型上的方法
    console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(cat))); // [ 'constructor', 'getKind' ]
  • 类不存在变量提升,因此在继承的时候父类必须在子类之前定义
    const foo = new Foo(); // ReferenceError: Foo is not defined
    class Foo {}

二、constructor

  • constructor是类的默认方法,它相当于ES5中的构造函数,当我们使用new命令生成对象实例时,会自动调用该方法。
  • 一个类必须有constructor方法,如果没有显示定义,会默认添加一个空的constructor方法。
    class Animal {
    
    }
    // 等同于
    calss Animal {
        constructor() {}
    }
  • constructor方法默认返回实例对象,不过也可以指定返回另一个对象。
    class Foo {
        constructor() {
            // 返回一个数组
            return new Array()
        }
        print() {
            console.log('124')
        }
    }
    
    // 实例对象不再是Foo类的实例,而是Array的实例
    const foo = new Foo();
    console.log(foo instanceof Foo); // false
    console.log(foo instanceof Array); // true
    // 无法调用Foo类中的方法
    foo.print(); // TypeError: foo.print is not a function

三、this的指向

类的方法中如果含有this,则默认指向类的实例。但是如果单独使用该方法,可能会报错。

    class Foo {
        printName() {
            this.print('hahah');
        }
        print(text) {
            console.log(text);
        }
    }
    
    const foo = new Foo();
    // 将printName单独提出来
    const printName = foo.printName;
    // 此时printName中的this指向运行时所在的环境(这里是Window),找不到print方法
    printName(); // TypeError: Cannot read property 'print' of undefined

解决方法:

  • 在类的构造方法constructor中绑定this,当new一个实例的时候,会执行该方法
    class Foo {
        constructor() {
            // bind方法会创建一个新的绑定函数,绑定函数的执行上下文为this
            this.printName = this.printName.bind(this)
        }
        printName() {
            this.print('hahah');
        }
        print(text) {
            console.log(text);
        }
    }
    
    const foo = new Foo();
    const printName = foo.printName;
    printName(); // hahah
  • 使用箭头函数
    class Foo {
        constructor() {
            // 在实例对象上新增了一个方法printName
            this.printName = () => {
                this.print('lalal')
            }
        }
        printName() {
            this.print('hahah');
        }
        print(text) {
            console.log(text);
        }
    }
    
    const foo = new Foo();
    const printName = foo.printName;
    // 调用的是实例的printName,而不是原型上的printName
    printName(); // lalal

四、静态方法和静态属性

4.1 静态方法
  • 定义:静态方法指的是Class本身的方法,而不是prototype属性上的方法;

  • 语法: 在类的方法前加上static关键字;

  • 特点:

    • 类相当于实例的原型,默认情况下类中的所有方法都会被实例继承,但是静态方法不会被实例继承,而是通过类直接调用
        class Foo {
            // 静态方法
            static sayHi() {
                console.log('Hi')
            }
        }
        
        const foo = new Foo();
        // 实例调用静态方法会报错
        // foo.sayHi(); // TypeError: foo.sayHi is not a function
        Foo.sayHi(); // Hi
    
    • 父类的静态方法可以被子类的继承
        class Bar extends Foo {}
        Bar.sayHi(); // Hi
    
    • 静态方法可以通过super调用,因为当super作为对象使用时,在静态方法中指向父类
        class Bar extends Foo {
            static sayHello() {
                super.sayHi()
            }
        }
        Bar.sayHello(); // Hi
    
4.2 静态属性
  • 定义:静态属性值类本身的属性,而不是定义在实例对象上(this)的属性

  • 语法:

    • 目前只能使用Class.propname的写法,因为ES6规定,Class内部只有静态方法,没有静态属性
    // 添加静态属性prop
    Foo.prop = 1;
    
    const foo = new Foo();
    // 通过类访问
    console.log(Foo.prop); // 1
    // 不能通过实例访问
    console.log(foo.prop); // undefined
    
    • 提案:目前有一个提案,规定可以在Class内部使用static关键字+等式的方法为类添加静态属性
        class Foo {
            // 静态属性
            static prop = 1;
            // 提案也规定了Class的实例属性可以用等式写入类的定义之中
            name = 'Lily';
            constructor(){
                console.log(Foo.prop, this.name); // 1 Lily
            }
        }
    

五、new.target属性

ES6为new运算符添加了new.target属性,(在构造函数中)返回new命令所左右的构造函数。如果构造函数不是通过new命令调用的,那么new.target会返回undefined,因此可以使用该属性确定构造函数是如何调用的。

    function Person(name) {
        if (new.target === Person) {
            this.name = name;
        } else {
            throw new Error('必须使用new生成实例')
        }
    }
    const person1 = new Person('Lily');
    const person2 = Person('Lily'); // Error: 必须使用new生成实例
    class Foo {
        constructor() {
            console.log(new.target === Foo);
        }
    }
    new Foo(); // true



原文地址:https://www.cnblogs.com/jiafifteen/p/12201334.html