JavaScript中解析super关键字
虽互不曾谋面,但希望能和您成为笔尖下的朋友
以读书,技术,生活为主,偶尔撒点鸡汤
不作,不敷衍,意在真诚吐露,用心分享
点击左上方,可关注本刊
标星公众号(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关键字相关推荐
- 在JavaScript中解析JSON? [重复]
本文翻译自:Parse JSON in JavaScript? [duplicate] This question already has answers here : 这个问题已经在这里有了答案 : ...
- JavaScript中的“ this”关键字
JavaScript'this'关键字 (JavaScript 'this' keyword) The this keyword is widely used in JavaScript. It ha ...
- 在JavaScript中解析查询字符串[重复]
本文翻译自:Parse query string in JavaScript [duplicate] Possible Duplicate: 可能重复: How can I get query str ...
- 如何在javascript中解析带有两个小数位的浮点数?
本文翻译自:How to parse float with two decimal places in javascript? I have the following code. 我有以下代码. I ...
- JavaScript中的“ new”关键字是什么?
最初遇到JavaScript时, new关键字可能会造成很大的混乱,因为人们倾向于认为JavaScript并非面向对象的编程语言. 它是什么? 它解决什么问题? 什么时候合适,什么时候不合适? #1楼 ...
- JS/JavaScript中解析JSON --- JSON.parse()、JSON.stringify()以及$.parseJSON()使用详解
JS/JavaScript中解析JSON --- JSON.parse().JSON.stringify()以及$.parseJSON()使用详解 现在JSON格式在web开发中非常重要,特别是在使用 ...
- JavaScript中的This 关键字
This 关键字 重要的事情说三遍: 注:This指向哪个对象不取决于函数定义的位置,而取决于调用的位置 注:This指向哪个对象不取决于函数定义的位置,而取决于调用的位置 注:This指向哪个对象不 ...
- 取出url中的字符_如何在JavaScript中解析URL:例如主机名,路径名,查询,哈希?...
统一资源定位符(缩写URL)是对Web资源(网页,图像,文件)的引用.URL指定资源位置和检索资源的机制(http,ftp,mailto). 例如,这是此博客文章的URL: 通常,您需要访问URL的特 ...
- 深入理解JavaScript中的this关键字
在JavaScript中this变量是一个令人难以摸清的关键字,this可谓是非常强大,充分了解this的相关知识有助于我们在编写面向对象的JavaScript程序时能够游刃有余. 对于this变量最 ...
最新文章
- scala语言运行递归“分鱼”程序
- 理解系统底层的概念是多么重要
- 【CF应用开发大赛】微博社交简历
- 中国移动短信网关CMPP3.0 C#源代码:使用示例
- 【虚拟化】Dockerfile构建JDK镜像
- Xamarin Studio支持TypeScript开发
- MySQL出现慢日志超过2秒_MySQL慢日志功能分析及优化增强
- [导入]基类的复制控制函数
- 今日最佳:你爸爸给你取名的时候。。。
- css中会计算的属性,2017年12月聚合文章--calc() ---一个会计算的css属性 | 码友网
- aes加密算法python实现_Python基于pycrypto实现的AES加密和解密算法示例
- python能自学成功吗-想自学Python,如何才能坚持下来?
- Android5.0 netd架构流程
- 计算机应用基础doc,计算机应用基础.doc
- usr目录linux,linux之usr目录的概述
- 微软快捷键截图_所有最好的Microsoft Excel键盘快捷键
- 【正点原子I.MX6U-MINI应用篇】5、嵌入式Linux在LCD上显示BMP、JPG、PNG图片
- 微信小程序实现旋转动画效果
- 使用golang进行PDF处理,go-tika。就是这个是个warp的封装的版本。ledongthuc/pdf 的开源项目,速度快,解析中文也非常好。可以解析出简历PDF内容
- Fintech趣店总部(厦门)技术招聘
热门文章
- SQL Server 2008基础(自学笔记)
- dubbo面试题整理
- IPSec IKE协商(图解协议+包分析)【IPSec协议簇学习笔记一】
- Unity框架之对象池GameObjectPool
- 4.1重载加号运算符
- jQuery 属性的操作
- Application of Office 365 in Education Management (2)
- java通过邮件找回密码_SpringMVC实现通过邮件找回密码功能
- oracle里面的terminate,pg_cancel_backend() 与pg_terminate_backend()
- oracle非聚簇索引,聚簇索引(Clustered Index)和非聚簇索引 (Non- Clustered Index)