前言

此篇文章是看了阮老师的es6教程,看到super关键字的时候觉得有必要总结梳理一下,原文还是参考 ECMAScript 6入门

正文

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

1.当作函数使用

super作为函数调用时,代表父类的构造函数。ES6 要求 ,子类的构造函数必须执行一次super函数。

即作为 函数 使用时下面的代码时 固定使用套路

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

上面代码中的super()代表的谁??

子类 B 的构造函数中的super(),代表 B调用父类 A 的构造函数执行。

注意⚠️: 虽然这里的 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

还有一点需要注意 ⚠️ :

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

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

总结一下:

当super 作为函数的时候需要注意以下三点:

  1. 子类的构造函数必须执行一次super函数。
// 再次重申,这是固定写法
class A {
constructor() {}
} class B extends A {
constructor() {
super();// 这里表示 A.constructor()
}
}
  1. 子类的构造函数中的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();

我们发现 在子类 Bsuper.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指向父类的原型对象。

⚠️注意点 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⚠️: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⚠️:通过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作为对象在普通方法中应用时:

  1. 子类中的super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。
  2. 在子类普通方法中通过 super 调用父类的方法时,方法内部的 this 指向当前的子类实例。
  3. 通过 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 ⚠️

在子类的静态方法中通过 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指向当前的子类,而不是子类的实例。

总之

  1. super作为函数,super()代表的就是父类构造函数,里面的this就是类的实例。
  2. super作为对象,在普通的方法中super.的语法指向的是父类的原型对象,在静态方法中使用super.语法的话就去父类的静态方法中找就行了。至于this指向问题,记住一点:如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,所以静态方法中的this只会指类而不是实例。

你真的了解[super ]关键字吗?的更多相关文章

  1. Java super关键字活用

    在实际开发中我们要自定义组件,就需要继承自某个组件类,如果我们自定义的这个组件类也需要像被继承的这个组件类一样,拥有丰富的构造方法. 关键字super的作用就更加显得尤为重要了,你可以在堆砌自己自定义 ...

  2. 12.super关键字

    ①在java中使用super关键字来调用父类的成分

  3. this、super关键字

    this关键字 this 关键字用来表示当前对象本身,或当前类的一个实例,通过 this 可以调用本对象的所有方法和属性. public class Demo{ public int x = 10; ...

  4. Java基础-super关键字与this关键字

    用super调用父类构造方法 类如果没有显式声明构造方法,则自动生成无参数的默认构造方法. 1.先用一个无参数的父类构造方法验证一下, 执行子类构造方法会自动调用父类的构造方法.测试代码: class ...

  5. 使用 Object.create 创建对象,super 关键字,class 关键字

    ECMAScript 5 中引入了一个新方法:Object.create().可以调用这个方法来创建一个新对象.新对象的原型就是调用 create 方法时传入的第一个参数: var a = {a: 1 ...

  6. 方法重写和方法重载;this关键字和super关键字

    1:方法重写和方法重载的区别?方法重载能改变返回值类型吗? 方法重写: 在子类中,出现和父类中一模一样的方法声明的现象. 方法重载: 同一个类中,出现的方法名相同,参数列表不同的现象. 方法重载能改变 ...

  7. 继承进一步使用,以及super关键字

    目标: 1)掌握子类对象实例化过程 2)掌握方法覆盖概念和实现. 3)掌握super关键字的作用. 一,子类对象实例化过程 子类对象在实例化之前,必须先调用父类中的构造方法,再调用子类中的构造方法. ...

  8. OC基础--self关键字&super关键字

    PS:OC中的self关键字可以与C#中的this关键字区分记忆,虽然区别还是很大的. OC中的super关键字指的是父类指针 一.self关键字必须了解的知识: 1.使用场合:只能用在方法中(对象方 ...

  9. 面向对象编程(十)——继承之Super关键字及内存分析

    Super关键字

随机推荐

  1. mysqlslap 压测工具使用说明

    PS:今天一同事问我有木有比较靠谱的mysql压力测试工具可用.其实mysql自带就有一个叫mysqlslap的压力测试工具,还是模拟的不错的.下面举例说说.mysqlslap是从5.1.4版开始的一 ...

  2. cJson 创建 读取

    关于c语言操作json,cjson还挺好用,许多操作已经帮开发员封装好了,使用起来很方便.资源下载地址为:http://sourceforge.net/projects/cjson/在test.c文件 ...

  3. Spark2 Dataset之视图与SQL

    // 创建视图 data.createOrReplaceTempView("Affairs") val df1 = spark.sql("SELECT * FROM Af ...

  4. html的base标签

    提示:请把 <base> 标签排在 <head> 元素中第一个元素的位置,这样 head 区域中其他元素就可以使用 <base> 元素中的信息了. 注释:如果使用了 ...

  5. Cloudstack云平台实践

    laaS平台的虚拟化 利用率高 资源整合 节约电能 节约空间 灾难恢复 CloudStack是一个开源的具有高可用性及扩展性的云计算平台.支持管理大部分主流的hypervisor,如KVM虚拟机,Xe ...

  6. linux:用户及文件权限管理

    学习内容来自实验楼.莫烦python.CSDN 一.Linux 用户管理 1. 查看用户 who am i 或者who mom likes who -a:打印所有能打印的  who -d :打印死掉的 ...

  7. AmazonOrder xml web语义化

    XML Processing Modules — Python 3.7.1 documentation https://docs.python.org/3.7/library/xml.html#xml ...

  8. php 实现栈结构

    一.栈的定义及知识 1.定义:栈又称为栈或者堆叠,是计算机科学中的一种特殊的串列形式的抽象数据类型,特殊之处在于只允许在链表或者数组的一端(堆栈顶端指针,又称 "top")加入数据 ...

  9. BigDecimal精度与相等比较的坑

    先想一下,创建BigDecimal对象的时候一般是怎么创建的? new一个,传进去值 BigDecimal.valueOf方法,传进去值 作为一个数字类型,经常有的操作是比较大小,有一种情况是比较是否 ...

  10. dbms_stats.gather_table_stats详解

     dbms_stats.gather_table_stats 统计表,列,索引的统计信息(包含该表的自身-表的行数.数据块数.行长等信息:   列的分析--列值的重复数.列上的空值.数据在列上的分布情 ...