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

更新日期: 2020-03-16阅读: 1.9k标签: 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,我们可以不这么做吗?那么在我们调用它时不传入 props,又会发生什么呢?会有其他的缺省参数吗?接来下我们就解开这一系列谜题。

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

值得注意的是,在调用父类的构造函数之前,你是不能在 constructor 中使用 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!');
}

但是我们并未想起 this.greetColleagues 在 super() 给 this.name 赋值前就已经执行。this.name 此时甚至尚未定义。可以看到,这样的代码难以往下推敲。

为了避免落入这个陷阱,JavaScript 强制你在使用 this 之前先行调用 super。让父类来完成这件事情!:

constructor(props) {
  super(props);
  // 能使用 `this` 了
  this.state = { isOn: true };
}

这里留下了另一个问题:为什么要传入 props ?

你或许会想到,为了让 React.Component 构造函数能够初始化 this.props,将 props 传入 super 是必须的:

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

这几乎就是真相了 — 确然,它是 这样做 的。

但有些扑朔迷离的是,即便你调用 super() 的时候没有传入 props,你依然能够在 render 函数或其他方法中访问到 this.props。(如果你质疑这个机制,尝试一下即可)

那么这是怎么做到的呢?事实证明,React 在调用构造函数后也立即将 props 赋值到了实例上:**

// 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 赋值。但如此为之会使得 this.props 在 super 调用一直到构造函数结束期间值为 undefined。

// React 內部
class Component {
  constructor(props) {
    this.props = props;
    // ...
  }
}
// 你的程式碼內部
class Button extends React.Component {
  constructor(props) {
    super(); // 我们忘了传入 props
    console.log(props);      // {}
    console.log(this.props); //  未定义
  }
  // ...
}

如果在构造函数中调用了其他的内部方法,那么一旦出错这会使得调试过程阻力更大。这就是我建议开发者一定执行 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 更新的新版 contextTypes)的时候,context 是作为第二个参数传入构造函数的。

那么为什么我们不能转而写成 super(props, context) 呢?我们当然可以,但 context 的使用频率较低,因而并没有掘这个坑。

class fields proposal 出台后,这些坑大部分都会自然地消失在没有显示的定义构造函数的情况下,以上的属性都会被自动地初始化。这使得像 state = {} 这类表达式能够在需要的情况下引用 this.props 和 this.context 的内容。

然而,有了 Hooks 以后,我们几乎就不需要 super 和 this 了。但那就是另一个下午的茶点了。

转载自https://overreacted.io/  

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

ES6 类继承 和 super的使用

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

谈谈super(props) 的重要性

我听说 Hooks 最近很火。讽刺的是,我想用一些关于 class 组件的有趣故事来开始这篇文章。你觉得如何?本文中这些坑对于你正常使用 React 并不是很重要。 但是假如你想更深入的了解它的运作方式,就会发现实际上它们很有趣。

js中的super的使用

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

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

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

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指向实例对象,在构造函数上定义的属性和方法相当于定义在类实例上的,而不是原型对象上

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