你真的了解[super ]关键字吗?
栏目: JavaScript · 发布时间: 7年前
内容简介:此篇文章是看了阮老师的es6教程,看到
此篇文章是看了阮老师的es6教程,看到 super
关键字的时候觉得有必要总结梳理一下,原文还是参考ECMAScript 6入门。
正文
super
这个关键字,既可以当作函数使用,也可以当作对象使用。
1.当作函数使用
super
作为函数调用时,代表父类的构造函数。 ES6
要求 ,子类的构造函数必须执行一次 super
函数。
即作为 函数
使用时下面的代码时 固定使用套路
:
class A {
constrctor(){
}
}
class B extends A {
constructor() {
super();
}
}
复制代码
上面代码中的super()代表的谁??
子类 B
的构造函数中的 super()
,代表 B
调用父类 A
的构造函数执行。
注意:warning:: 虽然这里的 super()
代表了的 父类 A
的构造函数,但是返回的却是 子类 B
的实例,即 super()
内部的this 指的是 B, 因此 super()
在这里相当于 A.prototype.constructor.call(this)
。
用一个大栗子来证明我的论点:
class A {
constrctor(){
console.log(new.target.name)
}
}
class B extends A{
constructor(){
super()
}
}
new A() // A
new B() // B
复制代码
在这段热气腾腾的代码中, new.target
指向当前正在执行的函数。
啰嗦一下:
new
是从构造函数生成的实例对象的命令。ES6 为 new
命令引入了一个 new.target
属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。
可以看到,在 super()
执行时,它指向的是子类 B
的构造函数,而不是父类 A
的构造函数。即 super()
内部的 this 指向的是 B
。
还有一点需要注意:warning: :
作为函数时,super()只能用在子类的构造函数中,用在其他地方报错。
// 错误写法
class A {}
class B extends A {
m() {
super(); // 报错
}
}
复制代码
总结一下:
当super 作为函数的时候需要注意以下三点:
-
子类的构造函数必须执行一次
super函数。
// 再次重申,这是固定写法
class A {
constructor() {}
}
class B extends A {
constructor() {
super();// 这里表示 A.constructor()
}
}
复制代码
-
子类的构造函数中的
super()代表的是 子类调用父类的构造函数执行,这时候super()中的this,即父类.constructor中的this,指向的是子类。
3.super()只能用在子类的构造函数之中,用在其他地方就会报错。
2.super作为对象时
super
作为对象时,在普通方法中,指向父类的原型对象,在静态方法中指向父类。
2.1 super作为对象在普通方法中应用
上代码:
class A {
p(){
return 2
}
}
class B extends A {
constrctor(){
super();
console.log(super.p());//2
}
}
let b = new B();
复制代码
我们发现 在子类 B
中 super.p()
执行结果为 2
。我们猜测这里的 supsuper.p === A.prototype.p
,验证一下发现结果是 true
:
class A {
p() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.p===A.prototype.p); // true
}
}
let b = new B();
复制代码
也就是说这个时候 super
在普通的方法中,指向的是 A.prototype
即子类中的 super
指向父类的原型对象。
:warning: 注意点 1.
:由于子类中的 super
指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过 super
调用的。
class A {
constructor() {
this.s = 3;
}
}
A.prototype.x = 2;
class B extends A {
constructor() {
super();
console.log(super.x) // 2 这里可以获取到父类原型上的x属性
}
get m(){
return super.s
}
}
let b = new B();
console.log(b.m)// undefined 不能获取到定义在父类实例上的s属性
复制代码
通过上面的代码我们发现:
子类 B
可以通过 super
获取到父类定义在原型上的属性,但是定义在父类 A
的实例上的属性,无法获取到。
注意点2:warning:: this指向
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();// 这里等同于 A.proptotype.print()
}
}
let b = new B();
b.m() // 2
复制代码
上面代码中, super.print()
虽然调用的是 A.prototype.print()
,但是 A.prototype.print()
内部的this指向子类B的实例,导致输出的是2,而不是1。也就是说,实际上执行的是 super.print.call(this)
。
注意点3:warning::
通过 super
进行赋值操作
由于 this
指向子类实例,所以如果通过 super
对某个属性赋值,这时 super
就是 this
,赋值的属性会变成子类实例的属性。
class A {
constructor() {
this.x = 1;
}
}
class B extends A {
constructor() {
super();
this.x = 2;
super.x = 3;// 此时的 super 就是 b
console.log(super.x); // undefined 等用于是 A.prototype.x
console.log(this.x); // 3
}
}
let b = new B();
复制代码
通过这两段代码我们发现了一个问题,当我通过 super
取值的时候取的是父类的原型上属性,但是当我通过 super
赋值的时候这时候 super
指向的是子类的实例。
总结一下:
通过上面的三个栗子得出, super
作为对象在普通方法中应用时:
-
子类中的
super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。 -
在子类普通方法中通过
super调用父类的方法时,方法内部的 this 指向当前的子类实例。 - 通过 super 对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性。
2.2 super作为对象在静态方法中应用
如果 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 指的是父类,Parent
super.myMethod(msg);
}
myMethod(msg) {
// 普通函数 此时 super 是指 Parent.prototype
super.myMethod(msg);
}
}
Child.myMethod(1); // static 1
var child = new Child();
child.myMethod(2); // instance 2
复制代码
上面代码中,super在静态方法之中指向父类,在普通方法之中指向父类的原型对象。
注意点1 :warning:
在子类的静态方法中通过 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();// A.print 中的this指向当前的子类
}
}
B.x = 3;
B.m() // 3
复制代码
上面代码中,静态方法 B.m
里面, super.print
指向父类的静态方法。这个方法里面的 this
指向的是 B
,而不是 B
的实例。
总结一下:
在子类的静态方法中通过 super
调用父类的方法时,方法内部的 this
指向当前的子类,而不是子类的实例。
以上所述就是小编给大家介绍的《你真的了解[super ]关键字吗?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 从对象头出发了解Synchronized关键字
- 番外篇2-基本规范、注释、static关键字、import关键字
- 说说iOS中的常用的关键字static ,class(仅限Swift关键字)
- Golang 关键字
- 2019 关键字
- golang关键字
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据挖掘
(美)Jiawei Han、(加)Micheline Kamber、(加)Jian Pei / 范明、孟小峰 / 机械工业出版社 / 2012-8 / 79.00元
数据挖掘领域最具里程碑意义的经典著作 完整全面阐述该领域的重要知识和技术创新 这是一本数据挖掘和知识发现的优秀教材,结构合理、条理清晰。本书既保留了相当篇幅讲述数据挖掘的基本概念和方法,又增加了若干章节介绍数据挖掘领域最新的技术和发展,因此既适合初学者学习又适合专业人员和实践者参考。本书视角广阔、资料翔实、内容全面,能够为有意深入研究相关技术的读者提供足够的参考和支持。总之, 强烈推荐......一起来看看 《数据挖掘》 这本书的介绍吧!