类的super的作用

  派生类的方法可以通过super关键字引用它们的原型。这个关键字只能在派生类中使用,而且仅限于类构造函数、实例方法和静态方法内部。
  在类构造函数中使用super可以调用构造函数。

class Vehicle{
    constructor() {
        this.hasEngine = true
    }
}
class Bus extends Vehicle{
    constructor(){
        // 不要在调用super之前引用this,否则会抛出错误
        super(); //相当于super.constructor
        console.log(this instanceof Vehicle); //true
        console.log(this); //Bus {hasEngine: true}
    }
}
new Bus()

  在静态方法中可以通过super调用继承的类上调用的方法

class Vehicle{
    static identify(){
        console.log("vehicle");
    }
}

class Bus extends Vehicle{
    static identify(){
        super.identify();
    }
}

Bus.identify() //vehicle

注意:
  ES6给类构造函数和静态方法添加了内部特性[[HomeObject]],这个特性是一个指针,指向定义该方法的对象。这个指针是自动赋值的,而且只能在JavaScript引擎内部访问。super始终会定义为[[HomeObject]]

以上内容摘抄自红宝书第四版258-259页

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

  1. 当作函数使用
class B extends A{
    constructor(){
        super(); 
    }
}

  在constructor中必须调用super方法,因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工,而super就代表了父类的构造函数。super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里类似于A.prototype.constructor.call(this,props),但不相同。

class A{
    constructor (){
        console.log(new.target.name); //new.target指向当前正在执行的函数
    }
}
class B extends A{
    constructor(){
        super(); 
    }
}

new A(); //A
new B(); //B

  可以看到,在super()执行时,它指向的是子类B的构造函数,而不是父类A的构造函数。也就是说,super()内部的this指向的是B。
2. 当作对象使用
  在普通方法中,指向父类的原型对象;在静态方法中,指向父类

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

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

let b = new B()

  子类B当中的super().c,就是将super当作一个对象使用。这时,super在普通方法之中,指向A.prototype,所以super.c()就相当于A.prototype.c()
  通过super调用父类的方法时,super会绑定子类的 this

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

class B extends A{
    constructor(){
        super();
        this.x = 2;
    }
    m(){
        super.s()
    }
}
let b = new B()
b.m(); //2

  super.s()虽然调用的是A.prototytpe.s(),但是A.prototytpe.s()会绑定子类Bthis,导致输出的是 2,而不是 1。也就是说,实际上执行的是super.s.call(this)
  由于绑定子类的this,所以如果通过super 对某个属性赋值,这时super就是 this,赋值的属性会变成子类实例的属性。

class A{
    constructor(){
        this.x = 1
    }
}

class B extends A{
    constructor(){
        super();
        this.x = 2
        super.x = 3
        console.log(super.x); //undefined
        console.log(this.x); //3
    }
}
let b = new B

  super.x赋值为3,这时等同于对this.x赋值为3。而当读取super.x的时候,调用的是A.prototype.x,但是并没有x方法,所以返回indexfined
  注意,使用super的时候,必须显式指定是作为函数。还是作为对象使用,否则会报错。

class A{
    
}
class B extends A{
    constructor(){
        super();
        console.log(super);  //'super' keyword unexpected here
    }
}

  console.log(super)当中的super,无法看出是作为函数使用,还是作为对象使用,所以JavaScript引擎解析代码的时候就会报错。但是,如果能清晰的表明super的数据类型,就不会报错。
  由于对象总是继承其他对象的,所以可以在任意一个对象中,使用super关键字.
以下内容摘抄自红宝书第四版260-261页
在使用super时要注意几个问题:

  1. super只能在派生类构造函数和静态方法中使用
class Vehicle{
    constructor(){
        super();  //'super' keyword unexpected here
    }
}
  1. 不能单独引用super关键字,要么用它调用构造函数,要么用它引用静态方法
class Vehicle {}
class Bus extends Vehicle{
    constructor(){
        console.log(super); //'super' keyword unexpected here
    }
}
  1. 调用super()会调用父类构造函数,并将返回的实例赋值给this
class Vehicle{

}
class Bus extends Vehicle{
    constructor(){
        super();
        console.log(this instanceof  Vehicle);
    }
}

new Bus(); //true
  1. super()的行为如同调用构造函数,如果需要构造函数传参,则需要手动传入。
class Vehicle {
    constructor(licensePlate){
        this.licensePlate = licensePlate
    }
}

class Bus extends Vehicle{
    constructor(licensePlate){
        super(licensePlate)
    }
}
console.log(new Bus("xxxxxx")); //Bus {licensePlate: "xxxxxx"}
  1. 如果没有定义类构造函数,在实例化派生类时会调用super(),而且会传入所有传给派生类的参数
class Vehicle {
    constructor(licensePlate){
        this.licensePlate = licensePlate
    }
}

class Bus extends Vehicle{
    
}
console.log(new Bus("xxxxxxx")); //Bus {licensePlate: "xxxxxxx"}
  1. 在类构造函数中,不能在调用super()之前引用this
class Vehicle{

}

class Bus extends Vehicle{
    constructor(){
        console.log(this);
    }
}

new Bus() //Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
  1. 如果在派生类中显示了定义了构造函数,则要么必须在其中调用super(),要么必须在其中返回一个对象。
class Vehicle{
     
}

class Car extends Vehicle{
    
}

class Bus extends Vehicle{
    constructor(){
        super();
    }
}

class Van extends Vehicle{
    constructor(){
        return {}
    }
}

console.log(new Car()); //Car {}
console.log(new Bus()); //Bus {}
console.log(new Van()); //{}

参考文章:
红宝书第四版258-261页
简书-BluesCurry:理解 es6 class 中 constructor 方法 和 super 的作用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值