class 的继承

1.简介

Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

1.jpg

上面代码定义了一个Student类,该类通过extends关键字,继承了Person类的所有属性和方法。但是由于没有部署任何代码,所以这两个类完全一样,等于复制了一个Person类。下面,我们在Student内部加上代码。

1.jpg

子类的constructor中出现了super关键字,它在这里表示父类的构造函数,用来新建父类的this对象。

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。

1.jpg

不调用super方法就报错,没有this



ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

如果子类没有定义constructor方法,这个方法会被默认添加,代码如下。也就是说,不管有没有显式定义,任何一个子类都有constructor方法。

1.jpg

上面代码中,子类Student没有定义constructor,但还是继承了父类的属性name和age。

子类没有定义constructor自然也就没有调用super()方法,这时候子类中是不能用this关键字的,用了会报错,this is not defined

这是因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例。
1.jpg

不先调用super()方法,子类中就不能用this

下面是生成子类实例的代码。


1.jpg

new 一个学生小明,8岁,三年级。
小明是学生的一个实例,true。 小明是学生
小明是人的一个实例,true。 小明是人

父类的静态方法,也会被子类继承。

1.jpg



2.Object.getPrototypeOf

Object.getPrototypeOf方法可以用来从子类上获取父类。

因此,可以使用这个方法判断,一个类是否继承了另一个类。

1.jpg



可以看到 Student类继承了Person类。




3.super关键字

super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。

第一种情况,super作为函数调用时,代表父类的构造函数。

ES6 要求,子类的构造函数必须执行一次super函数。

// 定义类

class Person{
    
}

class Student extends Person{
    constructor(){
        super();
    }
}

上面代码中,子类B的构造函数之中的super(),代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错。

注意,super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)。

class A {
  constructor() {
    console.log(new.target.name);
  }
}
class B extends A {
  constructor() {
    super();
  }
}
new A() // A
new B() // B

上面代码中,new.target指向当前正在执行的函数。可以看到,在super()执行时,它指向的是子类B的构造函数,而不是父类A的构造函数。也就是说,super()内部的this指向的是B。

作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错。

class A {}

class B extends A {
  toString() {
    super(); // 报错
  }
}

上面代码中,super()用在B类的toString方法之中,就会造成句法错误。


第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

class A {
    toString() {
        return 2;
    }
}

class B extends A {
  constructor() {
    super();
    console.log(super.toString()); // 2
  }
}

let b = new B();

上面代码中,子类B当中的super.toString(),就是将super当作一个对象使用。这时,super在普通方法之中,指向A.prototype,所以super.toString()就相当于A.prototype.toString()



这里需要注意,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。

1.jpg

上面代码中,age是父类A实例的属性,super.age就引用不到它。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 基本用法 Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多...
    庸者的救赎阅读 3,118评论 0 2
  • Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。 co...
    木中木阅读 2,144评论 0 0
  • class的基本用法 概述 JavaScript语言的传统方法是通过构造函数,定义并生成新对象。下面是一个例子: ...
    呼呼哥阅读 9,532评论 3 11
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,898评论 18 399
  • 从去年开始,我就对自己说,不再写婆婆妈妈的事了,有娃后,婚姻里惊险刺激的头三年过去了,就是过去了。是时候该关注点有...
    射手座恶魔阅读 5,825评论 28 53