你真的了解[super ]关键字吗?

栏目: JavaScript · 发布时间: 6年前

内容简介:此篇文章是看了阮老师的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 作为函数的时候需要注意以下三点:

  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 指向父类的原型对象。

: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 作为对象在普通方法中应用时:

  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 :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 ]关键字吗?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Docker——容器与容器云(第2版)

Docker——容器与容器云(第2版)

浙江大学SEL实验室 / 人民邮电出版社 / 2016-10 / 89.00元

本书根据Docker 1.10版和Kubernetes 1.2版对第1版进行了全面更新,从实践者的角度出发,以Docker和Kubernetes为重点,沿着“基本用法介绍”到“核心原理解读”到“高级实践技巧”的思路,一本书讲透当前主流的容器和容器云技术,有助于读者在实际场景中利用Docker容器和容器云解决问题并启发新的思考。全书包括两部分,第一部分深入解读Docker容器技术,包括Docker架......一起来看看 《Docker——容器与容器云(第2版)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

html转js在线工具
html转js在线工具

html转js在线工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具