首页

Javascript

Html
Css
Node.js
Electron
移动开发
小程序
工具类
服务端
浏览器相关
前端收藏
其他
关于
公司注册

谈谈super关键字有什么作用?

2019年08月21日 发布 阅读(3221) 作者:Jerman

MDN上的定义

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

super.propsuper[expr]表达式在类和对象字面量任何方法定义中都是有效的。

在构造函数中使用时,super关键字将单独出现,并且必须在使用this关键字之前使用。super关键字也可以用来调用父对象上的函数。

  1. super([arguments]);
  2. // 调用 父对象/父类 的构造函数
  3. super.functionOnParent([arguments]);
  4. // 调用 父对象/父类 上的方法

ES6的子类class中为什么一定要使用super?

ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。

参考:new一个对象时,发生了什么?

ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面,然后再用子类的构造函数修改this。所以必须先调用super方法,否则javascript引擎会报错。

如:

  1. class A {}
  2. class B extends A {
  3. constructor(){
  4. // super()
  5. }
  6. }
  7. const C = new B();

上面代码,在通过new关键字创建一个实例的时候会报如下错误:

  1. constructor() {
  2. ^
  3. ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

根本原因: 前面讲过,子类class实例的构建是基于父类实例,而只有super方法才能调用父类实例

super()作为方法调用时,只能在constructor里调用,且只能调用一次,否则会报错

super()返回的是什么?

作为方法时返回

返回的是子类的实例,通过下面代码,也可以看到返回的是子类B的实例,

  1. class A {}
  2. class B extends A {
  3. constructor(){
  4. const sp = super()
  5. this.sp = sp;
  6. this.name = 'B';
  7. console.log(sp===this) // 打印:true
  8. }
  9. getName(){
  10. console.log(this.sp); // 打印:B { sp: [Circular], name: 'C' }
  11. }
  12. }
  13. const C = new B();
  14. C.name = 'C'
  15. C.getName();

作为对象时返回

super作为对象时,在普通方法中,指向父类的原型对象

  1. class A {
  2. constructor(){
  3. this.name = '';
  4. }
  5. // 普通方法
  6. getName(){
  7. return 'A'
  8. }
  9. }
  10. class B extends A {
  11. constructor(){
  12. const sp = super()
  13. this.sp = sp;
  14. }
  15. getName(){
  16. this.name = 'B'
  17. // super作为对象,调用普通方法getName
  18. console.log(super.getName()) //打印: A
  19. }
  20. }
  21. const C = new B();
  22. C.name = 'C'
  23. C.getName();

上面的结果可以看出,super.getName()调用的是父类A的普通方法getName

在静态方法中,指向父类

  1. class A {
  2. constructor(){
  3. this.name = '';
  4. }
  5. static getName(){
  6. return 'static A'
  7. }
  8. getName(){
  9. return 'A'
  10. }
  11. }
  12. class B extends A {
  13. constructor(){
  14. const sp = super()
  15. this.sp = sp;
  16. }
  17. static getName(){
  18. // 相当于执行A.getName()
  19. console.log(super.getName()) // 打印: static A
  20. }
  21. getName(){
  22. this.name = 'B'
  23. // 相当于执行new A().getName()
  24. console.log(super.getName()) // 打印: A
  25. }
  26. }
  27. B.getName();
  28. const C = new B();
  29. C.name = 'C'
  30. C.getName();

super底层发生了什么?

编辑上面的代码,看看

  1. 'use strict';
  2. var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
  3. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  4. function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
  5. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
  6. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  7. var A = function () {
  8. function A() {
  9. _classCallCheck(this, A);
  10. this.name = '';
  11. }
  12. _createClass(A, [{
  13. key: 'getName',
  14. value: function getName() {
  15. return 'A';
  16. }
  17. }], [{
  18. key: 'getName',
  19. value: function getName() {
  20. return 'static A';
  21. }
  22. }]);
  23. return A;
  24. }();
  25. var B = function (_A) {
  26. _inherits(B, _A);
  27. function B() {
  28. var _this;
  29. _classCallCheck(this, B);
  30. var sp = (_this = _possibleConstructorReturn(this, (B.__proto__ || Object.getPrototypeOf(B)).call(this)), _this);
  31. _this.sp = sp;
  32. return _this;
  33. }
  34. _createClass(B, [{
  35. key: 'getName',
  36. value: function getName() {
  37. this.name = 'B';
  38. // 相当于执行new A().getName()
  39. console.log(_get(B.prototype.__proto__ || Object.getPrototypeOf(B.prototype), 'getName', this).call(this));
  40. }
  41. }], [{
  42. key: 'getName',
  43. value: function getName() {
  44. // 相当于执行A.getName()
  45. console.log(_get(B.__proto__ || Object.getPrototypeOf(B), 'getName', this).call(this));
  46. }
  47. }]);
  48. return B;
  49. }(A);
  50. B.getName();
  51. var C = new B();
  52. C.name = 'C';
  53. C.getName();

编译工具: https://es6console.com/

参考

MDN: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/super

版权声明:本站文章除特别声明外,均采用署名-非商业性使用-禁止演绎 4.0 国际 许可协议,如需转载,请注明出处