谈谈super(props) 的重要性

更新日期: 2019-02-14阅读: 3.8k标签: super

我听说 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,并在提示消息中添加Person的name:

 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.props 或 this.context 的引用(如果有必要的话)。

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

原文:https://overreacted.io/why-do... 

 

链接: https://www.fly63.com/article/detial/2013

ES6 类继承 和 super的使用

ES6中继承的子类中,如果使用构造函数constructor()那么就必须使用 super()方法初始化,这样下面才可以调用this关键字。super()只能用在子类的构造函数之中,用在其他地方就会报错。

js中的super的使用

super()相当于Parent.prototype.constructor.call(this)ES5的继承,实质上是先创造子类的实例对象this,然后再将父类的方法添加到this上(Parent.call(this)). ES6的继承

ES6 class继承与super关键词深入探索

在ES6版本之前,JavaScript语言并没有传统面向对象语言的class写法,ES6发布之后,Babel迅速跟进,广大开发者也很快喜欢上ES6带来的新的编程体验。当然,在这门“混乱”而又精妙的语言中,许多每天出现我们视野中的东西却常常被我们忽略。

为什么我们要写 super(props) ?

据说 Hooks 势头正盛,不过我还是想略带调侃地从 class 的有趣之处开始这篇博客。可还行?这些梗对于使用 React 输出产品并不重要

jses6语法:class类 class继承 super关键字

Class可以通过extends关键字实现继承,这比ES5通过修改原型链实现继承,super关键字既可以当做函数使用,也可以当做对象使用,当做函数使用的时候,代表的是父类的构造函数

es6中class类、super和estends关键词

JavaScript 语言在ES6中引入了 class 这一个关键字,在学习面试的中,经常会遇到面试官问到谈一下你对 ES6 中class的认识,同时我们的代码中如何去使用这个关键字,使用这个关键字需要注意什么,这篇来总结一下相关知识点。

面试官:this和super有什么区别?this能调用到父类吗?

this 和 super 都是 Java 中的关键字,都起指代作用,当显示使用它们时,都需要将它们放在方法的首行(否则编译器会报错)。this 表示当前对象,super 用来指代父类对象

ES6中class方法及super关键字

记录下class中的原型,实例,super之间的关系,构造器中的this指向实例对象,在构造函数上定义的属性和方法相当于定义在类实例上的,而不是原型对象上

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!