谈谈JavaScript中super(props)的重要性

作者:疯狂的技术宅 时间:2024-04-30 09:56:11 

我听说 Hooks 最近很火。讽刺的是,我想用一些关于 class 组件的有趣故事来开始这篇文章。你觉得如何?

本文中这些坑对于你正常使用 React 并不是很重要。 但是假如你想更深入的了解它的运作方式,就会发现实际上它们很有趣。

开始第一个。

首先在我的职业生涯中写过的super(props) 自己都记不清:


class Checkbox extends React.Component {
constructor(props) {
 super(props);
 this.state = { isOn: true };
}
// ...
}

当然,在类字段提案 (class fields proposal) 中建议让我们跳过这个开头:


class Checkbox extends React.Component {
state = { isOn: true };
// ...
}

在2015年 React 0.13 增加对普通类的支持时,曾经打算用这样的语法。定义constructor和调用super(props) 始终是一个临时的解决方案,可能要等到类字段能够提供在工程学上不那么 * 的替代方案。

不过还是让我们回到前面这个例子,这次只用ES2015的特性:


class Checkbox extends React.Component {
constructor(props) {
 super(props);
 this.state = { isOn: true };
}
// ...
}

为什么我们要调用super? 可以调用它吗? 如果必须要调用,不传递prop参数会发生什么? 还有其他参数吗? 接下来我们试一试:

在 JavaScript 中,super 指的是父类的构造函数。(在我们的示例中,它指向React.Component 的实现。)

重要的是,在调用父类构造函数之前,你不能在构造函数中使用this。 JavaScript 是不会让你这样做的:


class Checkbox extends React.Component {
constructor(props) {
 // 这里还不能用 `this`
 super(props);
 // 现在可以用了
 this.state = { isOn: true };
}
// ...
}

为什么 JavaScript 在使用this之前要先强制执行父构造函数,有一个很好的理由能够解释。 先看下面这个类的结构:


class Person {
constructor(name) {
 this.name = name;
}
}
class PolitePerson extends Person {
constructor(name) {
 this.greetColleagues(); //这行代码是无效的,后面告诉你为什么
 super(name);
}
greetColleagues() {
 alert('Good morning folks!');
}
}

如果允许在调用super之前使用this的话。一段时间后,我们可能会修改greetColleagues,并在提示消息中添加Personname


greetColleagues() {
 alert('Good morning folks!');
 alert('My name is ' + this.name + ', nice to meet you!');
}

但是我们忘记了super()在设置this.name之前先调用了this.greetColleagues()。 所以此时this.name还没有定义! 如你所见,像这样的代码很难想到问题出在哪里。

为了避免这类陷阱,JavaScript 强制要求:如果想在构造函数中使用this,你必须首先调用super。 先让父类做完自己的事! 这种限制同样也适用于被定义为类的 React 组件:


constructor(props) {
 super(props);
 // 在这里可以用 `this`
 this.state = { isOn: true };
}

这里又给我们留下了另一个问题:为什么要传props参数?

你可能认为将props传给super是必要的,这可以使React.Component的构造函数可以初始化this.props


// Inside React
class Component {
constructor(props) {
 this.props = props;
 // ...
}
}

这与正确答案很接近了 —— 实际上它就是这么做的。

但是不知道为什么,即便是你调用super时没有传递props参数,仍然可以在render和其他方法中访问this.props。 (不信你可以亲自去试试!)

这是究竟是为什么呢? 事实证明,在调用构造函数后,React也会在实例上分配props


// Inside React
const instance = new YourComponent(props);
instance.props = props;

因此,即使你忘记将props传给super(),React 仍然会在之后设置它们。 这是有原因的。

当 React 添加对类的支持时,它不仅仅增加了对 ES6 类的支持。它的目标是尽可能广泛的支持类抽象。 目前还不清楚 ClojureScript、CoffeeScript、ES6、Fable、Scala.js、TypeScript或其他解决方案是如何相对成功地定义组件的。 所以 React 故意不关心是否需要调用super()—— 即使是ES6类。

那么这是不是就意味着你可以写super()而不是super(props)呢?

可能不行,因为它仍然是令人困惑的。 当然,React 稍后会在你的构造函数运行后分配this.props, 但是在调用super() 之后和构造函数结束前这段区间内this.props仍然是未定义的:


// Inside React
class Component {
constructor(props) {
 this.props = props;
 // ...
}
}
// Inside your code
class Button extends React.Component {
constructor(props) {
 super(); //我们忘记了传递 props 参数
 console.log(props);   // {}
 console.log(this.props); // undefined
}
// ...
}

如果这种情况发生在从构造函数调用的某个方法中,可能会给调试工作带来很大的麻烦。 这就是为什么我建议总是调用super(props) ,即使在没有必要的情况之下:


class Button extends React.Component {
constructor(props) {
 super(props); // 传递了 props 参数
 console.log(props);   // {}
 console.log(this.props); // {}
}
// ...
}

这样就确保了能够在构造函数退出之前设置好this.props

最后一点是长期以来 React 用户总是感到好奇的。

你可能已经注意到,当你在类中使用Context API时(无论是旧版的contextTypes或在 React 16.6中新添加的 contextType API),context 会作为第二个参数传递给构造函数。

那么为什么我们不写成super(props, context) 呢? 我们可以这样做,但是使用context的频率较低,所以这个坑并没有那么多影响。

根据类字段提案的说明,这些坑大部分都会消失。 如果没有显式构造函数,则会自动传递所有参数。 这允许在像state = {} 这样的表达式中包含对this.propsthis.context的引用(如果有必要的话)。

而有了 Hooks 之后,我们甚至不再有superthis。不过这是另外一个的话题了。

来源:https://segmentfault.com/a/1190000018084870

标签:javascript,super(props),react,hooks
0
投稿

猜你喜欢

  • jQuery动态添加删除select项(实现代码)

    2024-04-22 12:59:04
  • opencv python 基于KNN的手写体识别的实例

    2021-02-22 13:03:02
  • 日期垂直排列的两种技巧

    2009-08-28 12:38:00
  • 用DW8制作网页中常用的过度效果

    2007-10-16 12:56:00
  • Python简单实现区域生长方式

    2023-08-08 12:07:38
  • python3.6中anaconda安装sklearn踩坑实录

    2023-03-16 19:17:15
  • javascript设计模式交流(一)Singleton Pattern

    2007-11-29 13:20:00
  • TensorFlow 滑动平均的示例代码

    2023-10-25 15:41:28
  • 在 Jupyter 中重新导入特定的 Python 文件(场景分析)

    2021-01-30 01:16:57
  • python字符串定义的三种方式

    2022-05-27 08:17:57
  • mysql回表致索引失效案例讲解

    2024-01-21 01:28:48
  • python批量生成身份证号到Excel的两种方法实例

    2022-05-16 14:25:43
  • 谈谈从phpinfo中能获取哪些值得注意的信息

    2023-11-23 23:52:17
  • mysql生成指定位数的随机数及批量生成随机数的方法

    2024-01-16 18:22:22
  • Python中处理unchecked未捕获异常实例

    2022-08-03 23:49:54
  • MySQL5.7.10 安装文档教程详解

    2024-01-19 00:37:58
  • PHP 应用容器化以及部署方法

    2023-11-14 15:45:06
  • Centos7.4环境安装lamp-php7.0教程

    2023-11-16 03:07:24
  • MySQL WorkBench管理操作MySQL教程

    2024-01-14 10:32:13
  • 利用Python生成Excel炫酷图表

    2023-03-09 21:52:00
  • asp之家 网络编程 m.aspxhome.com