【问题标题】:Why isn't this allowed before super()为什么在 super() 之前不允许这样做
【发布时间】:2017-04-21 09:59:05
【问题描述】:

我一直在使用 React js 进行编码。我已经读过在 ES6 类中访问“this”,我们需要首先调用 super(props),我想知道为什么会这样。我发现的答案主要是关于 Javascript 无法知道“this”是什么,除非超类叫做。我想知道这意味着什么,因为在构造函数之外,“this”被识别,我们不会每次都调用 super(props)。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { /* initial state */ };
  }
}

【问题讨论】:

  • 我认为,如果我错了,任何人都可以纠正我,在调用 super() 之前,不会创建实例,这意味着在此之前 this 不会指向任何东西
  • 我见过在 super({properties}) 之前使用 'this.{property}' 的代码。是不是在这种情况下使用了父级的属性?
  • 你必须调用 super()
  • @U.P ,如果你错了,你要求纠正 - 好吧,你是:)当你实例化一个类时,首先发生的事情是被实例化的类的原型被克隆,这个克隆是新的实例。只有在实例已经存在但处于未初始化状态后,原型链中的每个构造函数都会按顺序调用该实例,从 Object 构造函数到您使用 new 运算符调用的构造函数。
  • @U.P ,super 构造函数要在其他所有操作之前被调用,以确保一旦执行到达子类构造函数中的其余代码,实例就完全初始化了。

标签: javascript es6-class


【解决方案1】:

不幸的是,这真的很复杂。


短篇小说:在super()调用之前不允许在子类中访问this,因为在ES6中this是在基类中诞生的,因此super()是需要初始化它。

有关详细信息,请参阅15.6.2 Allocating and initializing instances1。作者是少数详细解释这一点的人之一。

以下是上述书籍1中的相关示例。

在引擎盖下,它大致如下所示。

// Base class: this is where the instance is allocated
function Person(name) {
    // Performed before entering this constructor:
    this = Object.create(new.target.prototype);

    this.name = name;
}
···

function Employee(name, title) {
    // Performed before entering this constructor:
    this = uninitialized;

    this = Reflect.construct(Person, [name], new.target); // (A)
        // super(name);

    this.title = title;
}

【讨论】:

    【解决方案2】:

    构造函数默认返回'this'。根据 oops 概念,子类总是通过 super() 调用从父类继承“this”对象。因此,如果我们尝试在没有 super 调用的子类中使用它,它将引发错误。 如果我们从子类返回除 'this' 之外的任何内容,则不需要调用 super()。 我已经通过一些简单的例子进行了解释。

    示例 1

    class A {
      constructor() {
        this.a = 0;
      }
    }
    
    class B extends A {
        constructor() {
            console.log(this);
        }
    }
    const instanceA = new A();
    console.log(instanceA) // A {a: 0}
    const instanceB = new B();
    console.log(instanceB) // Error: Must call super constructor in derived class before 
    accessing 'this' or returning from derived constructor 
    

    示例 2

    class A {
      constructor() {
        this.a = 0;
      }
    }
    
    class B extends A {
        constructor() {
          return {b: 3}
        }
    }
    const instanceA = new A();
    console.log(instanceA) // A {a: 0}
    const instanceB = new B();
    console.log(instanceB) // Object {b: 3}
    

    示例 3

    class A {
      constructor() {
        this.a = 0;
      }
    }
    
    class B extends A {
        constructor() {
          super()
        }
    }
    
    const instanceB = new B();
    console.log(instanceB) // B {a: 0}
    

    【讨论】:

      【解决方案3】:

      构造方法是一种特殊的方法,用于创建和初始化一个用类创建的对象。一个类中只能有一个名为“constructor”的特殊方法。如果类包含多次出现的构造函数方法,则会抛出 SyntaxError。构造函数可以使用 super 关键字调用父类的构造函数。

      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

      这意味着如果你有class MyComponent extends React.Component,你总是需要super() 来定义它。

      如果不指定构造方法,则使用默认构造方法。

      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor#Default_constructors

      父类的构造函数应该在this之前调用,以便在子类开始配置this之前完成this的配置。否则超类构造函数可能会得到子类修改的this。超类不应该对子类有所了解。这就是为什么在构造函数中调用super() 应该在访问this 之前。

      【讨论】:

      • 我觉得这两个引用根本没有回答问题,你的评论只是重复了事实,没有解释。
      • 好吧。那我补充几句吧。在子类开始配置this 之前,应首先调用超类的构造函数以完成this 的配置。否则超类构造函数可能会得到子类修改的this。超类不应该对子类有所了解。这就是为什么 super() 在构造函数中调用应该在访问 this 之前。
      • 为什么不写“super()”的调用不是隐式的?有充分的理由吗?
      • @Alex,子类的构造函数可能采用与超类构造函数不同的参数。然后仅当构造函数不接受 args 时才使 super() 显式是不一致的(并且也难以检测 - 例如,如果它使用 arguments 会怎样)。老实说,我认为 ES6 正在破坏 javascript,而 no-this-before-super 是众多原因之一。
      猜你喜欢
      • 1970-01-01
      • 2011-08-17
      • 2013-09-07
      • 1970-01-01
      • 2020-05-01
      • 2011-10-14
      • 2019-01-24
      • 1970-01-01
      • 2017-02-24
      相关资源
      最近更新 更多