ES6-Class类

书籍参考:《ECMAScript 6入门》 作者:阮一峰

文档参考:MDN

1.概念

ES6提供了Class语句用于更的理解语义以及更接近传统的编程语言的写法。Class可以当作ES5构造函数的一个语法糖。

传统的构造函数以及继承方法如下面这样来写的:

function Getname() {
    this.name = 'wyz';
    this.age = '29';
}

// 如果我们需要定义一个给所有基于Getname构造函数使用的方法
// 那么我们必须通过prototype对象上定义

Getname.prototype.getName = function(){
    return (`Name: ${this.name}, Age: ${this.age}`);
}

let gname = new Getname();

gname.getName(); //"Name: wyz, Age: 29"

通过上面的方法来创建一个“类”,对比其他语言是差距很大的,而且很难理解,ES6提供了一个新的语句Class来创建类。

class Getname{
    constructor(){
        this.name = 'wyz';
        this.age = '29';
    }

    getName(){
        return (`Name: ${this.name}, Age: ${this.age}`);
    }
}

let gname = new Getname();

gname.getName();    //"Name: wyz, Age: 29"

通过ES6的Class语句更能清晰的表达出类,这与传统的语言声明类很相似。在class中,constructor方法是一个构造函数,类似于我们构造函数中编写给实例初始化的一些属性方法,而在constructor之外定义的方法都是定义在原型上面的公用方法,这就很能理解为什么Class是构造函数的语法糖了。

gname.constructor === Getname; // true

gname.getName === Getname.prototype.getName; // true

在使用Class语句的时候,需要注意下面几个点:

  1. 在定义类的时候,方法与方法之间不需要逗号间隔,在定语方法的前面也不需要添加function关键字。
  2. 在使用定义类之前需要实例化,并且需要加上new关键字,这与构造方法一致。
  3. 类的所有方法都是定义在prototype属性上的,并且可以通过__proto__访问,同时也可以直接在上面对类进行添加方法。
  4. 一个方法必须有constructor,如果没有,会默认添加一个空的constructor。并且constructor默认返回实例对象即实例对象的指针this,我们可以显示的使用return语句改变默认动作。
  5. 类必须要使用前定义,不存在变量提升。
  6. 类的内部使用严格运行模式。
  7. 子类同时具备prototype__proto____proto__指向父类,而prototype__proto__属性,指向父类的原型也就是父类的prototype属性。

2.继承

Class之间的继承通过extends关键字来实现,这对比es5复杂的修改原型要容易得多,需要注意的是子类并没有this指针,子类的this是通过先调用父类的构造方法得到this然后在上面加工,所以在子类使用this指针前必须使用调用父类的构造方法。

这与es5的构造函数不一样,es5是先创建子类的this,然后在这个this上面添加方法与属性。

一个子类通过在构造方法中使用super()来调用父类构造方法创建this,如果没有只有constructor没有super(),那么将会在实例的时候出错,如果即没有constructorsuper(),那么会默认添加上。

class Getname{
    constructor(){
        this.name = 'wyz';
        this.age = '29';
    }

    getName(){
        return (`Name: ${this.name}, Age: ${this.age}`);
    }
}

class Getall extends Getname{
    constructor(){
        super();
        this.gender = 'male';
    }

    getAll(){
        return (`Name: ${this.name}, Age: ${this.age}, Gender: ${this.gender}`);
    }

}

let m = new Getall();   //继承了父类的初始化值。name: "wyz", age: "29", gender: "male"

m.getName(); //使用父类的方法。Name: wyz, Age: 29

3.Object.getPrototypeOf()

Object.getPrototypeOf()方法的作用是从子类上获取父类,那么就可以把这个方法拿来判断一个子类是否继承于一个类

Object.getPrototypeOf(Getall) === Getname; //true

4.类的静态方法

在定义类中的所有方法都是定义在prototype属性上的,那么就意味着所有的方法都会被继承,那如何来定义一个不被实例继承,而只能通过类本身调用的静态方法?ES6提供了static关键字。在需要不被继承静态方法前,但这个静态方法会被子类继承,因为子类的__proto__总是指向父类。

class Foo {
    static classMethod() {
        return 'hello'; 
    }
}

let foo = new Foo();

foo.classMethod();  //foo.classMethod is not a function

class Fow extends Foo {
}

Fow.classMethod();  // 'heelo'
Fow.__proto__.classMethod === Foo.classMethod; //true

5.类的静态属性

ES6只定义了类的静态方法并没有定义类的静态属性,所以如果要定义类的静态属性只能通过下面这样来定义:


class Foo{ } Foo.name = 'wyz';

但是ES7提出了一个议案,可以直接通过static关键字来定义类的静态属性,目前babel已经支持了。

class Foo{
    static name = 'wyz';
}

文完

文档信息