ECMAScript6入门:super到底是什么


前言

ES6 中的继承和 super 的用法大家都不会陌生,可是一问到 super 到底是什么,估计很对人都会回答不上来。在 ES6 中,super 是一个特殊的语法,而且它比 this 还要特殊,有很多用法上的限制。


一、super是什么?

MDN: super关键字用于访问和调用一个对象的父对象上的函数

二、super怎么用?

1.当做函数使用

super作为函数调用时,代表父类的构造函数。ES6要求,class继承中子类的构造函数必须执行一次super函数,否则JavaScript引擎会报错。
代码如下(示例):

class A {}

class B extends A {
  constructor() {
    super();
  }
}
1.super()返回的是子类的实例

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

var a=null
var b=null
class A{
	constructor(){
		console.log(new.target.name) //new.target指向正在执行的函数
	}
}

class B extends A{
	constructor(){
		a = super()
	}
}
b=new B //B
console.log(b===a)//true

可以看到当执行super()的时候,new.target.name返回B表明执行的是函数B而不是函数A,这说明在子类继承父类时super()的this指向子类。
b===a返回true,表明了super()虽然代表了父类A的构造函数,但返回的是子类B的实例。

2.super()只能在子类的构造函数中调用

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

class A {}

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

2.当做对象使用

1.在普通方法中,super指向父类的原型对象
class A {
p(){
	console.log('A.p')
	}
}

class B extends A {
  constructor() {
    super(); 
  }
  p(){
	console.log('B.p')
  }
  getP(){
	super.p()
	console.log(super.p===A.prototype.p)//true
	}
}
var b=new B
b.p()//B.P
b.getP()//A.P

在这里b.p()调用的是B类的p方法。b.getP()调用的是A类的p方法。注意到,super.p===A.prototype.p返回true。所以super当做对象使用,在普通方法中指向父类的原型。

(1)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

在这里,通过子类B的实例调用父类A的print()打印this.x,得到的是实例b的x属性的值2。也就是说,实际上执行的是super.print.call(this)

(2)由于this指向子类实例,所以如果通过super对某个属性赋值,赋值的属性会变成子类实例的属性。
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执行get操作时访问的是父类原型,由于父类原型中没有x属性所以super.x返回undefinedsuper.x=3执行set操作时相当于this.x=3,由于this指向子类实例,所以this.x打印的是3而不是2.

2.在静态方法中,指向父类。

代码如下(示例):

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

class Child extends Parent {
  static myMethod() {
    super.myMethod();
    console.log(super.myMethod===Parent.myMethod)//true
    console.log(super.myMethod===Parent.prototype.myMethod)//false
  }
}

Child.myMethod(); // static

在这里super.myMethod()相当于Parent.myMethod(),所以打印的值是static。再一个是,可以看到,super.myMethod===Parent.myMethod//truesuper.myMethod===Parent.prototype.myMethod//false这说明了super在静态方法之中指向父类而不是父类原型。

(1)在子类的静态方法中通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例。
class A{
	constructor(){
		this.x=1
	}
	static print(){
		console.log(this.x)
	}
}
class B extends A{
	constructor(){
		super()
		this.x=2
	}
	static print(){
		super.print()
	}

}
B.print()//undefined B.x
B.x=3
B.print()//3

这里B.print()静态方法里的super.print指向父类的静态方法,这个方法里的this指向子类B,而不是B的实例,即this.x===B.x。第一次B.print()时,B类没有静态属性x,只有实例属性x,所以打印的是undefined而不是2。设置B.x=3后,B类静态属性x值为3,所以B.print()打印的是3。

(2)使用super的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错。
super() //表示super作为函数使用
super.xxx //表示super作为对象使用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值