JS-学习ES6之- class 的继承

本文详细介绍了ES6中class的继承机制,包括如何使用super关键字进行父类方法的调用,以及Object.getPrototypeOf()方法用于获取父类。文章通过实例解释了super在普通方法和静态方法中的不同行为,并强调了子类构造函数中调用super的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

  • 简介
  • Object.getPropertyOf()
  • super 关键字

1、简介

class 可以通过 extends 关键字实现继承。

在子类继承父类的时候,在 constructor 中必须首先调用 super() 方法,然后才能使用 this

// 父类
class Point {
  constructor (x){
    this.x = x;
  }
  toString(){
    console.log('这种颜色耐脏!');
  }
}

// 子类
class ColorPoint extends Point {
  constructor(x, color){
    // 必须首先调用父类的constructor(x)
    super(x);
    this.color = color;
  }
  toString(){
    // 调用父类的toString()
    return this.color + ' ' + super.toString();
  }
}

子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错。这是因为子类自己的 this 对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用 super 方法,子类就得不到 this 对象。

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

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

class A {
  static hello(){
    console.log('hello world');
  }
}

class B extends A {

}

B.hello() // hello world

上面代码中,hello()A 类的静态方法, B 继承 A ,也继承了 A 的静态方法。

2、Object.getPrototypeOf()

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

Object.getPrototypeOf(ColorPoint) === Point
// true

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

3、super 关键字

super 这个关键字,既可以当作函数使用,也可以当作对象使用。

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

class A {}

class B extends A {
  constructor() {
    super();
  }
}

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

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

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

let b = new B();

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

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

class A {
  constructor(){
    this.p = 2; // p 为实例的属性
  }
}

class B extends A {
  get m(){
    return super.p;
  }
}

let b = new B();
b.m // undefined

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

ES6 规定,在子类普通方法中通过 super 调用父类的方法时,方法内部的 this 指向当前的子类实例。

class A {
  constructor (){
    this.x = 1;
  }
  print(){
    console.log(this.x);
  }
}

class B extends A {
  constructor(){
    super();
    this.x = 2;
  }
  m(){
    super.print();
  }
}

let b = new B();
b.m(); // 2

上面代码中,super.print() 虽然调用的是 A.prototype.print(),但是 A.prototype.print() 内部的 this 指向子类 B 的实例,导致输出的是2,而不是1。也就是说,实际上执行的是 super.print.call(this)

如果 super 作为对象,用在静态方法之中,这时 super 将指向父类,而不是父类的原型对象。

class Parent {
  static myMethod(msg) {
    console.log('static', msg);
  }

  myMethod(msg) {
    console.log('instance', msg);
  }
}

class Child extends Parent {
  static myMethod(msg) {
    super.myMethod(msg);
  }

  myMethod(msg) {
    super.myMethod(msg);
  }
}

Child.myMethod(1); // static 1

var child = new Child();
child.myMethod(2); // instance 2

上面代码中,super 在静态方法之中指向父类,在普通方法之中指向父类的原型对象。

另外,在子类的静态方法中通过 super 调用父类的方法时,方法内部的 this 指向当前的子类,而不是子类的实例。

class A {
  constructor() {
    this.x = 1;
  }
  static print() {
    console.log(this.x);
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
  }
  static m() {
    super.print();
  }
}

B.x = 3;
B.m() // 3

上面代码中,静态方法 B.m 里面,super.print 指向父类的静态方法。这个方法里面的 this 指向的是 B ,而不是 B 的实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值