当前位置: 首页 > news >正文

【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()关键字。

相关文章:

【ES6】Class继承-super关键字

目录 一、前言二、ES6与ES5继承机制区别三、super作为函数1、构造函数this1)、首先要明确this指向①、普通函数②、箭头函数③、注意事项 2)、其次要明确new操作符做了哪些事情 2、super()的用法及注意点1)、用法2)、注意点 四、s…...

做亚马逊测评不知道怎么找客户?这才是亚马逊测评的正确打开方式!

如今的跨境电商内卷严重,花费大量资金做广告推广的效果却微乎其微,这也是亚马逊测评迅速崛起的最根本原因。做亚马逊测评是近年来兴起的一种方式,许多卖家都需要大量的测评来提高自己的产品排名和信誉度。很多兄弟最近来问龙哥亚马逊测评怎么…...

传感器基础:传感器使用与编程使用(三)

目录 常用传感器讲解九--雨滴传感器具体讲解电路连接代码实现 常用传感器讲解十--光传感器根据亮度安排灯具体讲解电路连接代码实现 常用传感器讲解七--light cup(KY-008)具体讲解电路连接代码实现 常用传感器讲解十二--倾斜开关传感器(KY-02…...

深入浅出:分布式、CAP 和 BASE 理论(荣耀典藏版)

大家好,我是月夜枫,一个漂泊江湖多年的 985 非科班程序员,曾混迹于国企、互联网大厂和创业公司的后台开发攻城狮。 在计算机科学领域,分布式系统是一门极具挑战性的研究方向,也是互联网应用中必不可少的优化实践&…...

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…...

使用Docker快速安装grafana

Docker 提供了一个轻量级、易于部署的容器化解决方案&#xff0c;让您能够方便地在不同环境中运行应用程序。以下是在 Docker 中安装 Grafana 的基本步骤&#xff1a; 文章目录 使用Docker快速安装grafana如何使用Grafana步骤 1&#xff1a;连接数据源步骤 2&#xff1a;创建仪…...

excel 函数技巧

1&#xff1a;模糊查询 LOOKUP(1,0/FIND(F1062,Sheet1!C$2:Sheet1!C$9135),Sheet1!B$2:Sheet1!B$9135) 函数含义&#xff1a;寻找F列1062行和sheet1中的C2行到C9135行进行模糊查询&#xff0c;返回该行对应的B2行到B9135行的结果。未查到返回结果0 函数公式&#xff1a; LO…...

Ubuntu安装WordPress并使用Nginx作为Web服务器

在Ubuntu上安装和配置WordPress并使用Nginx作为Web服务器&#xff0c;以下是一个简单的操作流程&#xff1a; 步骤 1: 安装Nginx sudo apt update sudo apt install nginx 启动Nginx并设置开机自启&#xff1a; sudo systemctl start nginx sudo systemctl enable nginx …...

[Linux]Ubuntu noVNC使用

又到了逛大型程序员交友 网站的时间了&#xff0c;今天你准备好了吗。 今天要推荐的一个有趣的项目是noVNC setup好以后是这个样子的&#xff0c;可以在浏览器登陆vnc&#xff0c;不需要再安装一个vnc client. setup的过程比较简单&#xff0c;分为以下几步&#xff1a; 1. v…...

CSRF和SSRF原理、区别、防御方法

CSRF&#xff08;Cross-Site Request Forgery&#xff09;原理&#xff1a;CSRF是一种由攻击者构造形成&#xff0c;由服务端发起请求的一个安全漏洞。它是一种利用用户在已登录的网站中提交非法请求的行为&#xff0c;攻击者通过伪造用户提交的请求&#xff0c;将恶意请求发送…...

如何使用JMeter测试https请求

HTTP与HTTPS略有不同&#xff0c;所以第一次使用JMeter测试https请求时遇到了问题&#xff0c;百度一番后找到解决方法&#xff1a;加载证书。 下面内容主要记录这次操作&#xff0c;便于后续参考&#xff1a; 操作浏览器&#xff1a;谷歌 &#xff08;1&#xff09;下载被测…...

el-table 纵向垂直表头

<template><div class"element-main"><div> Element-ui 官方提供 table Demo</div><el-tableborderstyle"width: 100%":data"tableData"><el-table-column prop"courseName" label"课程信息&qu…...

python/pytorch读取数据集

MNIST数据集 MNIST数据集包含了6万张手写数字&#xff08;[1,28,28]尺寸&#xff09;&#xff0c;以特殊格式存储。本文首先将MNIST数据集另存为png格式&#xff0c;然后再读取png格式图片&#xff0c;开展后续训练 另存为png格式 import torch from torch.utils.data impor…...

IT安全:实时网络安全监控

了解庞大而复杂的网络环境并非易事&#xff0c;它需要持续观察、深入分析&#xff0c;并对任何违规行为做出快速反应。这就是为什么实时网络安全监控工具是任何组织 IT 安全战略的一个重要方面。 网络攻击和合规性法规是 IT 安全的两个主要驱动因素。同时&#xff0c;数据泄露…...

SQL server使用profiler工具跟踪语句

1.打开SQL server工具&#xff0c;在工具点击SQL server Profiler : 2.流程&#xff1a;暂停——清空———点击接口——启用&#xff1a; 3.找到对应的sql语句&#xff0c;复制到查询界面&#xff0c;开始查询数据&#xff1a;...

python实现一维傅里叶变换——冈萨雷斯数字图像处理

原理 傅立叶变换&#xff0c;表示能将满足一定条件的某个函数表示成三角函数&#xff08;正弦和/或余弦函数&#xff09;或者它们的积分的线性组合。在不同的研究领域&#xff0c;傅立叶变换具有多种不同的变体形式&#xff0c;如连续傅立叶变换和离散傅立叶变换。最初傅立叶分…...

表单(HTML)

<!DOCTYPE html> <html><head><meta charset"utf-8"><title>个人信息</title></head><body><h1>个人信息</h1><form><fieldset><legend>基本信息</legend><label for"…...

spripng 三级缓存,三级缓存的作用是什么? Spring 中哪些情况下,不能解决循环依赖问题有哪些

文章目录 前面有提到三级缓存&#xff0c;三级缓存的作用是什么&#xff1f;Spring 中哪些情况下&#xff0c;不能解决循环依赖问题&#xff1a; 前面有提到三级缓存&#xff0c;三级缓存的作用是什么&#xff1f; 上一篇&#xff1a;https://blog.csdn.net/weixin_44797327/a…...

elasticsearch系列六:索引重建

概述 我们再起初创建索引的时候由于数据量、业务增长量都并不大&#xff0c;常常不需要搞那么多分片或者说某些字段的类型随着业务的变化&#xff0c;已经不太满足未来需求了&#xff0c;再或者由于集群上面索引分布不均匀导致节点直接容量差异较大等等这些情况&#xff0c;此时…...

GitOps实践指南:GitOps能为我们带来什么?

Git&#xff0c;作为开发过程中的核心工具&#xff0c;提供了强大的版本控制功能。即便在写代码的时候稍微手抖一下&#xff0c;我们也能通过 Git 的差异对比&#xff08;diff&#xff09;轻松追踪到庞大工程中的问题&#xff0c;确保代码的准确与可靠。这种无与伦比的自省能力…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&&#xff1a;逻辑与 ||&#xff1a;逻辑或 &#xff01;&#xff1a;逻辑非 短路求值 位运算符 按位与&&#xff1a; 按位或 | 按位取反~ …...

OCR MLLM Evaluation

为什么需要评测体系&#xff1f;——背景与矛盾 ​​ 能干的事&#xff1a;​​ 看清楚发票、身份证上的字&#xff08;准确率>90%&#xff09;&#xff0c;速度飞快&#xff08;眨眼间完成&#xff09;。​​干不了的事&#xff1a;​​ 碰到复杂表格&#xff08;合并单元…...

【51单片机】4. 模块化编程与LCD1602Debug

1. 什么是模块化编程 传统编程会将所有函数放在main.c中&#xff0c;如果使用的模块多&#xff0c;一个文件内会有很多代码&#xff0c;不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里&#xff0c;在.h文件里提供外部可调用函数声明&#xff0c;其他.c文…...

【多线程初阶】单例模式 指令重排序问题

文章目录 1.单例模式1)饿汉模式2)懒汉模式①.单线程版本②.多线程版本 2.分析单例模式里的线程安全问题1)饿汉模式2)懒汉模式懒汉模式是如何出现线程安全问题的 3.解决问题进一步优化加锁导致的执行效率优化预防内存可见性问题 4.解决指令重排序问题 1.单例模式 单例模式确保某…...

Spring是如何实现无代理对象的循环依赖

无代理对象的循环依赖 什么是循环依赖解决方案实现方式测试验证 引入代理对象的影响创建代理对象问题分析 源码见&#xff1a;mini-spring 什么是循环依赖 循环依赖是指在对象创建过程中&#xff0c;两个或多个对象相互依赖&#xff0c;导致创建过程陷入死循环。以下通过一个简…...