【ES6】Class继承-super关键字

目录

  • 一、前言
  • 二、ES6与ES5继承机制区别
  • 三、super作为函数
    • 1、构造函数this
      • 1)、首先要明确this指向
        • ①、普通函数
        • ②、箭头函数
        • ③、注意事项
      • 2)、其次要明确new操作符做了哪些事情
    • 2、super()的用法及注意点
      • 1)、用法
      • 2)、注意点
  • 四、super作为对象
    • 1、super在子类普通方法中作为对象
    • 2、super在子类静态方法中作为对象
  • 五、总结

一、前言

类的继承可以通过extends实现,让子类继承父类的属性和方法,而在子类内部(构造函数constructor)必须调用super()实现继承(super()代表父类构造函数,调用之后生成一个继承父类的this对象)

二、ES6与ES5继承机制区别

  1. ES5的继承机制,是先创造一个独立的子类的实例对象,然后再将父类的方法添加到这个对象上面,即“实例在前,继承在后”
  2. ES6的继承机制,则是先将父类的属性和方法,加到一个空对象上面,然后再将该对象作为子类的实例,即“继承在先,实例在后”
  3. 所以ES6的继承必须先调用super(),这样会生成一个继承父类的this对象,没有这一步就无法继承父类。这意味着新建子类实例时,父类的构造函数必定会先运行一次
  4. super既可以作为函数使用,也可以作为对象使用,两种方法有很大的不同

三、super作为函数

super()作为函数调用时(子内constructor内部必须调用),代表父类的构造函数,调用之后生成的是子类的实例,即super()内部this指向的是子类的实例(由构造函数this指向可得出,构造函数内部this指向的是生成的实例,而super()调用之后生成的是子类实例)

1、构造函数this

1)、首先要明确this指向

①、普通函数

内部的this指向函数运行时所在的对象,也即指向函数的直接调用者

  • 如果一个函数在全局环境运行,this就指向顶层对象(浏览器中为window对象)
  • 如果一个函数作为某个对象的方法运行,this就指向那个对象
  • 如果一个函数作为构造函数,this指向它的实例对象
②、箭头函数

没有自己的this对象,内部的this就是定义时上层作用域中的this

③、注意事项

构造函数只能是普通函数,箭头函数不能作为构造函数(没有prototype),不可以对箭头函数使用new命令,否则会抛出一个错误

2)、其次要明确new操作符做了哪些事情

  1. 创建一个空对象instance({})
  2. 将instance的[[prototype]]属性指向构造函数fn的原型(即instance.[[prototype]] = fn.prototype),也即instance_ proto_要指向构造函数的原型prototype
  3. 执行构造函数,使用 call/apply 改变 this 的指向 => 让this指向创建出来的实例instance
  4. 若函数返回值的是对象类型则作为new方法的返回值返回,否则返回刚才创建的全新对象
function isObject (target) {
  return (typeof target === 'object' || typeof target === 'function') && target !== null
}
function myNew (fn, ...args) {
  // 使用Object.create(Y),就说明实例的__proto__指向了Y,即实例的原型对象是Y
  // Object.create():创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
  // 并且执行[[Prototype]]链接; 通过`new`创建的每个对象将最终被`[[Prototype]]`链接到这个函数的`prototype`对象上。
  const instance = Object.create(fn.prototype)
  // 改变this指向
  let res = fn.apply(instance, args)

  // 若res是个对象就直接返回,否则返回创建的对象
  // return res instanceof Object ? res : instance
  return this.isObject(res) ? res : instance
}

如果不用new操作符直接调用,那么构造函数就相当于普通函数了,执行对象就 是window(严格模式下为undefined),即this指向了window(严格模式下为undefined)

由此可以看出,构造函数内部this指向实例对象

2、super()的用法及注意点

1)、用法

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

class A {
  constructor() {
    // `new.target`指向当前正在执行的函数
    console.log(new.target.name);
  }
}
class B extends A {
  constructor() {
    super();
  }
}
new A() // A
// 在`super()`执行时,它指向的是子类`B`的构造函数,而不是父类`A`的构造函数
// 即`super()`内部的`this`指向的是`B`的实例
new B() // B

new.target指向被new调用的构造函数:在普通的函数调用中(函数调用),new.target的值undefined;在类的构造方法中,new.target指向直接被new执行的构造函数

2)、注意点

  • 子类的构造函数constructor内必须执行一次super函数
    • 这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,添加子类自己的实例属性和方法。如果不调用super()方法,子类就得不到自己的this对象
    • 新建子类实例时,父类的构造函数必定会先运行一次
  • 在子类的构造函数中,只有调用super()之后,才可以使用this关键字,否则会报错
    • super()调用之后才能让子类实例继承父类,然后才能在该基础上对子类实例进行属于它的特有操作
  • 不管有没有显示定义,任何一个子类都有constructor()方法,而且里边默认会调用super()
  • 作为构造函数时,super()只能用于在子类的构造函数之中,用在其他地方就会报错
    在这里插入图片描述
  • 使用super()的时候,必须显示指定是作为函数,还是作为对象使用,否则会报错
    在这里插入图片描述
  • 由于对象总是继承其他对象的,所以可以在任意一个对象中,使用super关键字
    在这里插入图片描述

四、super作为对象

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

1、super在子类普通方法中作为对象

当super作为对象在子类普通方法(非静态方法)中使用时,由于super指向父类的原型对象,所以定义在父类原型对象上的属性和方法都可以被访问到,而定义在父类实例上(父类构造函数this.xxx)的方法或属性无法被访问到

在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例,相当于执行的是super.fn.call(this)

下面的代码中,父类A有定义在原型对象的属性b和方法p(),还有定义在实例对象的属性a;可以看到的是,定义在原型对象的b和p都能被super.访问到,而定义在实例对象的a无法被访问到

class A {
  constructor() {
    this.a = 123 // 定义在A的实例上的属性a
  }
  // 定义在A.prototype上的方法
  p() {
    return 2;
  }
}

A.prototype.b = 123 // 定义在A原型对象的属性b

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2 => 相当于console.log(A.prototype.p())
  }
  
  getData() {
    console.log(super.a) // a定义在父类的实例对象上,所以为undefined
    console.log(super.b) // b定义在父类的原型对象上,所以为123
  }
}

let b = new B();

b.getData()

在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例,相对于执行的是super.fn.call(this)

class A {
  constructor() {
    this.x = 1; // 父类实例的x是1
  }
  print() {
    console.log(this.x);
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2; // 子类实例的x是2
  }
  m() {
    // 实际上执行的是`super.print.call(this)`
    super.print(); // 调用父类的方法,但是方法内部this是子类实例,所以输出2
  }
}

let b = new B();
b.m() // 2

由于this指向子类实例,所以如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性

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赋值为3,这时等同于对this.x赋值为3。而当读取super.x的时候,读的是A.prototype.x,所以返回undefined

2、super在子类静态方法中作为对象

当super作为对象在子类静态方法中使用时,这时super将指向父类,而不是父类的原型对象。在子类的静态方法中通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例

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

  myMethod(msg) {
    console.log('instance', msg);
  }
}

class Child extends Parent {
  static myMethod(msg) {
    // super作为对象在子类静态方法中使用,super指向的是父类
    // 也即要调用父类的myMethod方法,那就是父类的静态方法Parent.myMethod
    // 而属于一个类的方法,就是静态方法,也就是由static关键字定义的方法
    super.myMethod(msg); // 调用的是Parent.myMethod()
  }

  myMethod(msg) {
    // super作为对象在子类普通方法中使用,super指向的是父类的原型对象
    // 此时的super.myMethod()也即Parent.prototype.myMethod()
    // 由class语法糖和原来构造函数创建类的写法相对比可知
    super.myMethod(msg);
  }
}

Child.myMethod(1); // static 1

var child = new Child();
child.myMethod(2); // instance 2

五、总结

通过本文的介绍,我们了解了在ES6中使用extends关键字实现继承,并且学习了super()在子类中的用法和作用以及注意点。super()的正确使用可以让我们更加方便地在子类中调用父类的构造函数和方法,从而更加灵活地使用面向对象编程。希望本文能够帮助各个小伙伴更好地理解ES6中Class继承的super()关键字。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/274461.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity引擎有哪些优点

Unity引擎是一款跨平台的游戏引擎,拥有很多的优点,如跨平台支持、强大的工具和编辑器、灵活的脚本支持、丰富的资源库和强大的社区生态系统等,让他成为众多开发者选择的游戏开发引擎。下面我简单的介绍一下Unity引擎的优点。 跨平台支持 跨…

用Xshell连接虚拟机的Ubuntu20.04系统记录。虚拟机Ubuntu无法上网。本机能ping通虚拟机,反之不能。互ping不通

先别急着操作,看完再试。 如果是:本机能ping通虚拟机,反之不能。慢慢看到第8条。 如果是:虚拟机不能上网(互ping不通),往下一直看。 系统是刚装的,安装步骤:VMware虚拟机…

TCP 滑动窗口

滑动窗口(Sliding window)是一种流量控制技术。早期的网络通信中,通信双方不会考虑网络的拥挤情况直接发送数据。由于大家不知道网络拥塞状况,同时发送数据,导致中间节点阻塞掉包,谁也发不了数据&#xff0…

数据分析工具 Top 8

你能想象一个没有工具箱的水管工吗? 没有,对吧? 数据从业者也是如此。如果没有他们的数据分析工具,数据从业者就无法分析数据、可视化数据、从数据中提取价值,也无法做数据从业者在日常工作中做的许多很酷的事情。 根据你最感兴趣的数据科学职业——数…

VR与数字孪生:共同构筑未来的虚拟世界

随着科技的不断发展,数字孪生和VR已经成为当今热门的科技话题。作为山海鲸可视化软件的开发者,我们对这两者都有深入的了解。在此,我们将详细探讨数字孪生与VR的区别和联系。 首先,数字孪生(Digital Twin)…

深度学习 | DRNN、BRNN、LSTM、GRU

1、深度循环神经网络 1.1、基本思想 能捕捉数据中更复杂模式并更好地处理长期依赖关系。 深度分层模型比浅层模型更有效率。 Deep RNN比传统RNN表征能力更强。 那么该如何引入深层结构呢? 传统的RNN在每个时间步的迭代都可以分为三个部分: 1.2、三种深层…

pymol--常用指令

1. 导入蛋白质 1)Pymol> load name.pdb, name # 载入pdb文件,并命名,我还没试过 Pymol> fetch proteinID # 直接就加载了 我用的这个 右边选框,有A S H L C指令 2. 保存图片 2.1 直接输出PNG,在pymol后输…

k8s的网络类型

部署 CNI 网络组件 部署 flannel K8S 中 Pod 网络通信: ●Pod 内容器与容器之间的通信 在同一个 Pod 内的容器(Pod 内的容器是不会跨宿主机的)共享同一个网络命名空间, 相当于它们在同一台机器上一样,可以用 localho…

注意力机制在推荐模型中的应用

目录 一、注意力机制在推荐模型中的应用 二、AFM-引入注意力机制的FM 三、DIN、引入注意力机制的深度学习网络 四、强化学习与推荐系统结合 用户在浏览网页时,会选择性的注意页面的特定区域,忽视其他区域。 从17年开始,推荐领域开始尝试将…

ISP 状态机轮转和bubble恢复机制学习笔记

1 ISP的中断类型 ISP中断类型 SOF: 一帧图像数据开始传输 EOF: 一帧图像数据传输完成 REG_UPDATE: ISP寄存器更新完成(每个reg group都有独立的这个中断) EPOCH: ISP某一行结尾(默认20)就会产生此中断 BUFFER DONE: 一帧图像数据ISP完全写到DDR了 2 ISP驱动状态机 通过camer…

leaflet学习笔记-地图缩略图(鹰眼)的添加(三)

介绍 地图缩略图控件有助于用户了解主窗口显示的地图区域在全球、全国、全省、全市等范围内的相对位置,也称为鹰眼图。Leaflet提供了好几种地图缩略图控件,本文介绍其中一个最常用控件,即插件Leaflet.MiniMap。 依赖添加 这些地图控件都可以…

推荐系统中 排序策略 加权平均法

加权平均法是一种计算平均值的方法,其中每个元素都被分配一个权重,这个权重决定了该元素对平均值的贡献程度。在加权平均法中,每个元素的权重乘以其对应的数值,然后将这些加权值相加,最后除以总权重得到加权平均值。 …

STM32F407-14.3.10-表73具有有断路功能的互补通道OCx和OCxN的输出控制位-1x010

如上表所示,MOE1,OSSR0,CCxE1,CCxNE0时,OCx输出状态取决于OCx_REF与极性选择(CCxP),OCxN输出状态取决于GPIO端口上下拉状态。 --------------------------------------------------…

从实际业务问题出发去分析Eureka-Server端源码

文章目录 前言1.EnableEurekaServer2.初始化缓存3.jersey应用程序构建3.1注册jeseryFilter3.2构建JerseyApplication 4.处理注册请求5.registry() 前言 前段时间遇到了一个业务问题就是k8s滚动发布Eureka微服务的过程中接口会有很多告警,当时…

Neo4j 5建库

Neo4j 只有企业版可以运行多个库,社区版无法创建多个库,一个实例只能运行一个库; 如果业务需要使用多个库怎么办呢? 就是在一个机器上部署多个实例,每个实例单独一个库名 这个库的名字我们可以自己定义; …

andriod安卓水果商城系统课设

​ 一、目的及任务要求 随着当今社会经济的快速发展和网络的迅速普及,手机基本成为了每个人都随身携带的电子产品。传统的购物方式已经满足不了现代人日益追求便利及高效率的购物心理,而通过移动手机上的在线购物系统,可以便捷地甚至足不出…

缓存和缓冲的区别

近期被这两个词汇困扰了,感觉有本质的区别,搜了一些资料,整理如下 计算机内部的几个部分图如下 缓存(cache) https://baike.baidu.com/item/%E7%BC%93%E5%AD%98 提到缓存(cache),就…

【K8S 二进制部署】部署Kurbernetes的网络组件、高可用集群、相关工具

目录 一、K8S的网络类型: 1、K8S中的通信模式: 1.1、、pod内部之间容器与容器之间的通信 1.2、同一个node节点之内,不同pod之间的通信方式: 1.3、不同node节点上的pod之间是如何通信的呢? 2、网络插件一&#xff…

CGAL的三角形曲面网格的最短路径

该软件包提供了一种计算三角曲面网格上测地线最短路径的算法。 CGAL的Surface_mesh_shortest_path的原理是基于测地线最短路径算法。测地线是连接两个点之间的最短路径,它沿着曲面的法线方向前进。在三角曲面网格上,测地线算法可以用于找到从一点到另一…

【linux】如何查看服务器磁盘IO性能

查看服务器磁盘IO性能 在服务器运维过程中,了解服务器的磁盘IO性能是非常重要的。磁盘IO性能直接影响到服务器的响应速度和处理能力。本文将介绍如何使用dd命令来查看服务器磁盘IO性能。 1. 什么是dd命令? dd命令是Linux系统中的一个非常强大的工具&a…