虽互不曾谋面,但希望能和您成为笔尖下的朋友

以读书,技术,生活为主,偶尔撒点鸡汤

不作,不敷衍,意在真诚吐露,用心分享

点击左上方,可关注本刊

标星公众号(ID:itclanCoder)

如果不知道如何操作

点击这里,标星不迷路

前言

在写React中,用类class声明的组件,常常看到,React 组件内数据初始化往往放在constructor构造器函数里面,而子类继承React.Component,如果想要接收父组件的数据

那么必须要调用super(props),同时还需要让constructor构造器函数接收一个props参数,否则的话,在当前组件内是无法获取到外部组件传过来的值的

import React, { Component } from 'react'
import ReactDom from 'react-dom'class Button extends Component {constructor(props) {super(props)}render() {const { content } = this.props;return (<div><button>{content}</button></div>)}
}const container = document.getElementById('root');ReactDOM.render(<Button content="按钮" />, container);

在 React 中你经常会看到上面的代码,如果一个组件需要定义自己的构造函数,那么就一定要调用super(props),也就是继承了React.Component构造函数

至于为什么要调用super(props)方法,因为 Es6 采用的是先创建父类实例的 this,然后在用子类的构造函数修改 this

如果没有constructor构造器函数,调用super(),以及参数props,它是会报错的

在组件实例被构造之后,该组件的所有成员函数都无法通过this.props访问到父组件传递过来的props

下面一起来详细了解下super这个关键字

它不仅仅是一个关键字,还可以作为函数调用和对象使用

01

super作为函数调用

super 作为函数调用时, 它代表的指向的是父类的构造函数,在子类的构造函数必须执行一次super函数

也就是说,在子类继承父类中,如果super作为函数调用,只能写在子类的构造函数(constructor)里面,super代表的是父类的构造函数

class A {          // class关键字声明了一个类Aconstructor() {}
}class B extends A { // class关键字声明了类B继承自A类constructor() {   // constructor构造器函数super();        // 调用super()}
}new A() // A
new B() // B

在上面的代码中,子类 B 的构造函数之中的super(),它代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎就会报错。

注意super 虽然代表了父类 A 的构造函数,但是返回的是子类 B 的实例,即 super 内部的 this 指向的是 B 的实例 ::

这里的super相当于 A 类的constructor构造函数,会执行 A 的constructor,但是此时的this指向的是 B,所以打印出 B

换一种理解是:在执行super时,A 把 constructor 方法给了 B,此时 B 有了 A 的功能,但是执行的是 B 的内容,也就是 es5 的A.prototype.constructor.call(this)

而作为函数调用:它必须只能在子类的构造器函数(constructor)中进行调用的,如果放在其他地方,则是会报错的,如下所示:

class A {}class B extends A {fun() {super(); // 报错,super()不能放置在函数内调用}
}

在上面代码中,super()用在 B 类的fun方法之中,就会造成语法错误

02

super作为对象使用

super作为对象使用时,分为在普通方法中使用和在静态方法中使用

  • 普通方法使用:super指向父类的原型,即A.prototype,可以访问到原型上的方法和属性,也就是指向它父类的原型对象

class Animal {     // class关键字声明了一个Animal类constructor() {}parent(){  // 类Animal的一个方法console.log('我是父类Animal的普通方法... ...');}
}class Dog extends Animal {   // class关键字定义了Dog继承自Animal类constructor() {super()}watchHome(){            // 子类watchHome为Dog的方法super.parent() // 我是父类的普通方法// 等价于Animal.prototype.parent() // // 我是父类的普通方法}
}
const dog = new Dog()
dog.watchHome()

在上面代码中,子类 Dog 当中的 super.parent(), 就是将 super 当做一个对象使用, 此时, super在普通方法之中, 指向A.prototype, 所以super.parent()就相当于 Animal.prototype.parent()

注意

由于 super 指向父类的原型对象, 所以定义在父类实例上的方法或属性, 是无法通过 super 调用的

class Animal {constructor() {this.name = '父类上的实例上的属性'}
}class Dog extends Animal {watchHome(){return super.name}
}
const dog = new Dog()
console.log(dog.watchHome()); // undefined,定义在父类实例上的属性, 无法通过super调用

在上面代码中 name 是父类Animal实例的属性, super.name 就引用不到它

但如果属性是定义在父类的原型对象上,super就可以取到,如下所示

class Animal {}Animal.prototype.name = 'super实例上的属性'class Dog extends Animal {watchHome() {return super.name}
}const dog = new Dog()
console.log(dog.watchHome()); // super实例上的属性,可以拿到父类中原型下的name属性,定义在原型下的属性和方法都是公有的

而在ES6中规定, 在子类普通方法中, 通过 super 调用父类的方法时, 方法内部的 this 指向当前子类的实例. 如下所示

class A {constructor() {this.name = "itclanCoder";   // 定义在A类的私有属性}print() {   // 定义在A类的print私有方法console.log(this.name);}
}class B extends A {  // 类B继承自类Aconstructor() {super();         // 调用父类的superthis.name = "随笔川迹";     // 子类B的私有属性}m() {super.print();}
}let b = new B();
b.m() // 随笔川迹

super.print()虽然调用的是A.prototype.print(),但是A.prototype.print()内部的this指向子类 B 的实例 导致输出的是"随笔川迹",而不是"itclanCoder"。也就是说,实际上执行的是super.print.call(this)

这个特性很有用,可以用于重写(覆盖)父类的私有属性

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

class A {constructor() {this.name = "itclanCoder";}
}class B extends A {constructor() {super();this.name = "itclan";     // 子类B的私有属性super.name = "川川";console.log(super.name);  // undefined,super是父类,而name是父类的私有属性,无法直接访问console.log(this.name);   // 川川}
}let b = new B();

在上面面示例代码中,super.name赋值为"川川",这时等同于对this.name赋值为川川。而当读取super.name的时候,它读的是A.prototype.name,所以返回undefined

  • 如果用在静态方法之中

如果 super作为对象,用在静态方法之中,这时super将指向父类 , 而不是父类的原型对象

class Parent {static myMethod(msg) {  // 父类的方法之前加静态static关键字console.log('static1', msg);}myMethod(msg) {            // 父类的私有普通方法console.log('instance2', msg);}
}class Child extends Parent {  // 类child继承自篇Parentstatic myMethod(msg) {    // 子类的私有myMethod方法前声明staticsuper.myMethod(msg); // super在静态方法中指向父类, 而不是父类的原型}myMethod(msg) {super.myMethod(msg); // super在普通方法中指向父类的原型}
}Child.myMethod(1); // static1 1var child = new Child();
child.myMethod(2); // instance2 2

上面代码中,super 在静态方法之中指向父类,在普通方法之中指向父类的原型对象

另外,在子类的静态方法中通过 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();}
}B.x = 3;
B.m() // 3

上面代码中,静态方法B.m里面,super.print指向父类的静态方法。这个方法里面的this指向的是 B,而不是 B 的实例

 注意 

当使用 super 的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错

class A {}class B extends A {constructor() {super();console.log(super); // 报错}
}

在上面代码中,console.log(super)当中的super,是无法看出是作为函数使用,还是作为对象使用,所以 JavaScript 引擎解析代码的时候就会报错。这时,如果你能清晰地表明 super 的数据类型,就不会报错

class A {}class B extends A {constructor() {super();console.log(super.valueOf() instanceof B); // true}
}let b = new B();

在上面代码中,super.valueOf()表明 super 是一个对象,因此就不会报错。同时,由于 super 使得 this 指向 B 的实例,所以super.valueOf()返回的是一个 B 的实例

instanceof:的作用是A instanceof B,A 是否是由 B 实例化出来的,若是则为true,若不是则为false

  • MDN 相关参考文档

  • Es6 标准入门-super 关键字

总结

关于super关键字的使用,确实是复杂,主要的功能是可以在子类中调用父类的方法,在子类中调用父类的普通方法时,只能定义放置在构造器函数中,否则就会报错,无法直接引用父类的私有属性,但是却可以应用父类中的原型下的属性和方法

super关键字可以用于覆盖重写父类型中的属性,这也是它的一个作用,有时候在面试的时候,只要问到 class 继承,深一点话,就会问到super关键字

在做面向对象开发时,这个super也是非常重要的

揭露一些广告联盟骗局

2022-08-17

易时代流量统计变现

2022-08-16

VuePress中右侧全局添加侧边栏-实现置顶和置底

2022-08-10

vuejs中路由器的两种模式-哈希模式与历史模式

2022-08-05

点个在看你最好看

点击左下角阅读原文即可看更多内容

JavaScript中解析super关键字相关推荐

  1. 在JavaScript中解析JSON? [重复]

    本文翻译自:Parse JSON in JavaScript? [duplicate] This question already has answers here : 这个问题已经在这里有了答案 : ...

  2. JavaScript中的“ this”关键字

    JavaScript'this'关键字 (JavaScript 'this' keyword) The this keyword is widely used in JavaScript. It ha ...

  3. 在JavaScript中解析查询字符串[重复]

    本文翻译自:Parse query string in JavaScript [duplicate] Possible Duplicate: 可能重复: How can I get query str ...

  4. 如何在javascript中解析带有两个小数位的浮点数?

    本文翻译自:How to parse float with two decimal places in javascript? I have the following code. 我有以下代码. I ...

  5. JavaScript中的“ new”关键字是什么?

    最初遇到JavaScript时, new关键字可能会造成很大的混乱,因为人们倾向于认为JavaScript并非面向对象的编程语言. 它是什么? 它解决什么问题? 什么时候合适,什么时候不合适? #1楼 ...

  6. JS/JavaScript中解析JSON --- JSON.parse()、JSON.stringify()以及$.parseJSON()使用详解

    JS/JavaScript中解析JSON --- JSON.parse().JSON.stringify()以及$.parseJSON()使用详解 现在JSON格式在web开发中非常重要,特别是在使用 ...

  7. JavaScript中的This 关键字

    This 关键字 重要的事情说三遍: 注:This指向哪个对象不取决于函数定义的位置,而取决于调用的位置 注:This指向哪个对象不取决于函数定义的位置,而取决于调用的位置 注:This指向哪个对象不 ...

  8. 取出url中的字符_如何在JavaScript中解析URL:例如主机名,路径名,查询,哈希?...

    统一资源定位符(缩写URL)是对Web资源(网页,图像,文件)的引用.URL指定资源位置和检索资源的机制(http,ftp,mailto). 例如,这是此博客文章的URL: 通常,您需要访问URL的特 ...

  9. 深入理解JavaScript中的this关键字

    在JavaScript中this变量是一个令人难以摸清的关键字,this可谓是非常强大,充分了解this的相关知识有助于我们在编写面向对象的JavaScript程序时能够游刃有余. 对于this变量最 ...

最新文章

  1. scala语言运行递归“分鱼”程序
  2. 理解系统底层的概念是多么重要
  3. 【CF应用开发大赛】微博社交简历
  4. 中国移动短信网关CMPP3.0 C#源代码:使用示例
  5. 【虚拟化】Dockerfile构建JDK镜像
  6. Xamarin Studio支持TypeScript开发
  7. MySQL出现慢日志超过2秒_MySQL慢日志功能分析及优化增强
  8. [导入]基类的复制控制函数
  9. 今日最佳:你爸爸给你取名的时候。。。
  10. css中会计算的属性,2017年12月聚合文章--calc() ---一个会计算的css属性 | 码友网
  11. aes加密算法python实现_Python基于pycrypto实现的AES加密和解密算法示例
  12. python能自学成功吗-想自学Python,如何才能坚持下来?
  13. Android5.0 netd架构流程
  14. 计算机应用基础doc,计算机应用基础.doc
  15. usr目录linux,linux之usr目录的概述
  16. 微软快捷键截图_所有最好的Microsoft Excel键盘快捷键
  17. 【正点原子I.MX6U-MINI应用篇】5、嵌入式Linux在LCD上显示BMP、JPG、PNG图片
  18. 微信小程序实现旋转动画效果
  19. 使用golang进行PDF处理,go-tika。就是这个是个warp的封装的版本。ledongthuc/pdf 的开源项目,速度快,解析中文也非常好。可以解析出简历PDF内容
  20. Fintech趣店总部(厦门)技术招聘

热门文章

  1. SQL Server 2008基础(自学笔记)
  2. dubbo面试题整理
  3. IPSec IKE协商(图解协议+包分析)【IPSec协议簇学习笔记一】
  4. Unity框架之对象池GameObjectPool
  5. 4.1重载加号运算符
  6. jQuery 属性的操作
  7. Application of Office 365 in Education Management (2)
  8. java通过邮件找回密码_SpringMVC实现通过邮件找回密码功能
  9. oracle里面的terminate,pg_cancel_backend() 与pg_terminate_backend()
  10. oracle非聚簇索引,聚簇索引(Clustered Index)和非聚簇索引 (Non- Clustered Index)