【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 : instancereturn 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原型对象的属性bclass B extends A {constructor() {super();console.log(super.p()); // 2 => 相当于console.log(A.prototype.p())}getData() {console.log(super.a) // a定义在父类的实例对象上,所以为undefinedconsole.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); // undefinedconsole.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 1var child = new Child();
child.myMethod(2); // instance 2

五、总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Docker-Dev】Mac M2 搭建docker mysql

Mac M2 搭建Mysql 1、前言2、前置说明-Docker的代理访问3、前置说明-Mysql的镜像访问3.1、提取信息3.1.1、开启Mysql的实例3.1.2、Dokcer连接Mysql3.1.3、官方简易版的docker-compose3.1.4、如何登录mysql bash3.1.5、自定义my.cnf文件3.1.6、如何知道其他自定义配置项 4、M2安…

LeetCode刷题--- 有效的数独

个人主页:元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​​​http://t.csdnimg.cn/hKh2l 前言:这个专栏主…

什么是负载均衡?

负载均衡是指在计算机网络领域中,将客户端请求分配到多台服务器上以实现带宽资源共享、优化资源利用率和提高系统性能的技术。负载均衡可以帮助小云有效解决单个服务器容量不足或性能瓶颈的问题,小云通过平衡流量负载,使得多台服务器能够共同…

模式识别与机器学习(十二):Stacking

原理 在本次实验中以决策树、svm和随机森林为基学习器,以决策树为元学习器。 Stacking的做法是首先构建多个不同类型的一级学习器,并使用他们来得到一级预测结果,然后基于这些一级预测结果,构建一个二级学习器,来得到…

基于MATLAB的泊松分布,正态分布与伽玛分布(附完整代码与例题)

目录 一. 泊松分布 1.1 理论部分 1.2 MATLAB函数模型 1.3 例题 二. 正态分布 2.1 理论部分 2.2 MATLAB函数模型 2.3 例题 三. 伽玛分布 3.1 理论部分 3.2 MATLAB函数模型 3.3 例题 一. 泊松分布 1.1 理论部分 Poisson分布是离散的,其x值只能取自然数。…

const和constexpr

constexpr 是 C 11 标准新添加的关键字,在此之前(C 98/03标准)只有 const 关键字,其在实际使用中经常会表现出两种不同的语义(常量和只读)。 dis_1() 函数中的“const int x”只是想强调 x 是一个只读的变量…

Neo4j 5建库

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

Hadoop之HDFS 详细教程

1、HDFS概述 Hadoop 分布式系统框架中,首要的基础功能就是文件系统,在 Hadoop 中使用FileSystem 这个抽象类来表示我们的文件系统,这个抽象类下面有很多子实现类,究竟使用哪一种,需要看我们具体的实现类,在…

实战13 分配角色

目录 1、分配角色思路 2、分配角色回显接口实现 3、分配角色回显前端实现 3.1 编写前端api脚本代码 3.2 编写分配角色窗口代码 3.3 编写分配角色回显脚本代码 4、分配角色后端接口 4.1 UserRoleDTO 4.2 UserMapper 4.3 UserMapper.xml 4.4 UserService 4.5 UserServ…

ASP.Net实现新闻添加查询(三层架构,含照片)

目录 演示功能: 点击启动生成页面 点击搜索模糊查询 点击添加跳转新界面 ​编辑 点击Button添加 步骤: 1、建文件 ​编辑 2、添加引用关系 3、根据数据库中的列写Models下的XueshengModels类 4、DAL下的DBHelper(对数据库进行操作…

vue3+elementPlus:el-drawer新增修改弹窗复用

在el-drawer的属性里设置:title属性&#xff0c;和重置函数 //html<!-- 弹窗 --><el-drawerv-model"drawer":title"title":size"505":direction"direction":before-close"handleClose"><el-formlabel-posit…

数据挖掘(作业3

任务一 对以下数据集使用K均值聚类算法&#xff1a; 1&#xff09;观察实验结果是否符合预期&#xff1b; 2&#xff09;利用SSE标准确定K值&#xff1b; 3&#xff09;自行调参并观察对聚类结果的影响。 注意&#xff1a;需要把类别信息去掉。 “tutorial3_Data Explorat…

HTTP代理服务器:Go语言下的“网络翻译官”

开场白&#xff1a;在这个全球化的网络时代&#xff0c;有时我们需要一个“翻译官”来帮助不同系统、不同语言进行交流。今天&#xff0c;我们就来探讨如何使用Go语言&#xff0c;轻松实现这样一个角色——HTTP代理服务器&#xff0c;让我们的网络请求更加畅通无阻&#xff01;…

模式识别与机器学习-无监督学习-聚类

无监督学习-聚类 监督学习&无监督学习K-meansK-means聚类的优点&#xff1a;K-means的局限性&#xff1a;解决方案&#xff1a; 高斯混合模型&#xff08;Gaussian Mixture Models&#xff0c;GMM&#xff09;多维高斯分布的概率密度函数&#xff1a;高斯混合模型&#xff…

c语言用四种方式求解成绩之中最高分和最低分的差值

文章目录 一&#xff0c;题目二&#xff0c;方法1&#xff0c;方法一2&#xff0c;方法二3&#xff0c;方法三4&#xff0c;方法四 三&#xff0c;示例结果 一&#xff0c;题目 最高分最低分之差 输入n个成绩&#xff0c;换行输出n个成绩中最高分数和最低分数的差 输入 : 两行…

信息网络协议基础-IPv6协议

文章目录 概述为什么引入IP服务模型IPv4的可扩展性问题解决方法***CIDR(Classless Inter-Domain Routing, 无类别域间寻路)前缀汇聚***前缀最长匹配***NAT(网络地址转换)存在的问题解决方案路由表配置***局限性IPv6协议头标IPv6地址表示前缀类型单播地址链路局部地址(Link-Loca…

浅谈WPF之ToolTip工具提示

在日常应用中&#xff0c;当鼠标放置在某些控件上时&#xff0c;都会有相应的信息提示&#xff0c;从软件易用性上来说&#xff0c;这是一个非常友好的功能设计。那在WPF中&#xff0c;如何进行控件信息提示呢&#xff1f;这就是本文需要介绍的ToolTip【工具提示】内容&#xf…

自动备份B站Up主最新视频到百度网盘的Python脚本详解

自动备份B站Up主最新视频脚本详解&#xff08;Win和Linux有些不同&#xff09; 前言&#xff1a; 次篇文章启发于某些大胆的UP主&#xff08;老马&#xff09;的多次被封&#xff0c;并被下架一些视频。有些人并不能及时观看到&#xff0c;故写一个脚本自动下载最新视频。 &am…

中小企业运营难题:CRM系统为您解决!

​CRM如何帮助中小企业解决业务与团队之间的问题&#xff1f;它可以帮助企业获取潜在客户、数据储存管理、建立标准化流程、减少客户流失、促进客户沟通等。客户关系管理的核心理念要以客户为最主要的资源&#xff0c;提供全面的客户服务&#xff0c;满足客户要求&#xff0c;实…

【信息安全原理】——入侵检测与网络欺骗(学习笔记)

&#x1f4d6; 前言&#xff1a;在网络安全防护领域&#xff0c;防火墙是保护网络安全的一种最常用的设备。网络管理员希望通过在网络边界合理使用防火墙&#xff0c;屏蔽源于外网的各类网络攻击。但是&#xff0c;防火墙由于自身的种种限制&#xff0c;并不能阻止所有攻击行为…