ES6中super中的使用

14 篇文章 0 订阅

super在es6 class类中有两种主要使用方式,一种是做函数使用,一种是做对象使用

一.作为函数使用

在es6 class类的继承中,子类的中构造函数必须调用super() ,反则会报错

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


上面代码中, constructor 方法和 toString 方法之中,都出现了 super 关键字,它在这里表示父类的构造函数,
用来新建父类的 this 对象。


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


注意, 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 {
  m() {
    super(); // 报错
  }
}

二.super作为对象

1.在普通方法中,指向父类的原型对象;
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;
  }
}
class B extends A {
  get m() {
    return super.p;
  }
}
let b = new B();
b.m // undefined

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

如果属性定义在父类的原型对象上, super 就可以取到。

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

上面代码中,属性 x 是定义在 A.prototype 上面的,所以 super.x 可以取到它的值。

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)

由于 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 ,所以返回 undefined 。

2.用在静态方法之中,这时 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 的实例。

三、注意点

注意,使用 super 的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错。

class A {}
class B extends A {
  constructor() {
    super();
    console.log(super); // 报错
  }
}

上面代码中, console.log(super) 当中的 super ,无法看出是作为函数使用,还是作为对象使用,所以 JavaScript 引擎解析代码的时候就会报错。这时,如果能清晰地表明 super 的数据类型,就不会报错。

class A {}
class B extends A {
  constructor() {
    super();
    console.log(super.valueOf() instanceof B); // true
  }
}
let b = new B();

上面代码中, super.valueOf() 表明 super 是一个对象,因此就不会报错。同时,由于 super 使得 this 指向 B 的实例,所以 super.valueOf() 返回的是一个 B 的实例。

最后,由于对象总是继承其他对象的,所以可以在任意一个对象中,使用 super 关键字

var obj = {
  toString() {
    return "MyObject: " + super.toString();
  }
};
obj.toString(); // MyObject: [object Object]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@逆风boy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值