简体   繁体   English

原型继承:在子“类”构造函数中调用超级构造函数

[英]Prototype inheritance: Calling super constructor in sub “class” constructor function

I am trying to understand this piece of code and am wondering why we have a call to super constructor function in the sub "class" constructor function: 我试图理解这段代码,并且想知道为什么我们要在子“类”构造函数中调用超级构造函数:

function Person(name) {
   this.name = name;
}
// Other properties on Person prototype here...

function Employee(id, name) {
    Person.call(this, name);   // Why do we have to do this?
    this.id = id;
}
Employee.prototype = Object.create(Person.prototype);
// Other properties on Employee prototype here...

1) Why do we have Person.call(this, name) ? 1)为什么我们要有Person.call(this, name) In "Secrets of the Javascript Ninja", they do prototype inheritance WITHOUT calling the super constructor (the rest of the code is the same, except Object.create , but I understand why that is needed). 在“ Java忍者的秘密”中,它们无需调用超级构造函数即可进行prototype继承(其余代码是相同的,除了Object.create ,但我知道为什么需要这样做)。

So this is the prototype chain of your Employee (and Person) without the line Person.call(this,name) : 因此,这是您的Employee(和Per​​son)的原型链,没有一行Person.call(this,name)

|Person|                       |Employee|
|------|                       |--------|
|name  |                       |wage    |
|sex   |                       |id      |

   |                               |
   |                               |
   v                               v

|Person Prototype|             |Employee Prototype|
|----------------|             |------------------|
|walk()          |  <--------  |work()            |
|eat()           |             |goOnStrike()      |
|sleep()         |

   |
   |
   v

|Object|
|------|
| ***  |

Every time, you request a property of an employee, JavaScript looks for that property by traveling down the prototype chain. 每次您请求员工的财产时,JavaScript都会通过遍历原型链来查找该财产。 If you write this: 如果您这样写:

var employee = new Employee(1, "Jack White");
employee.walk();

JavaScript will look in employee , than in employee.[[prototype]] and then in employee.[[prototype]].[[prototype]] (following the arrow directions in the diagram) until it finds the property walk . 的JavaScript将寻找在employee ,比employee.[[prototype]]在然后employee.[[prototype]].[[prototype]] (以下图中的箭头方向),直到它找到该属性walk

As you can see, if you request the property name , JavaScript will not find it, because it is not in the prototype chain of employee . 如您所见,如果您请求属性name ,JavaScript将找不到它,因为它不在employee的原型链中。 So you have to make sure, to also "copy" local properties like name and sex . 因此,您必须确保还要“复制”本地属性,例如namesex

You do this by calling the constructor of Person with the context of the current Employee : 您可以通过使用当前Employee的上下文调用Person的构造函数来做到这一点:

function Employee(id, name) {
    Person.call(this, name);
    this.id = id;
}

which does essentially the same as if you would just copy all the code from inside of the Person constructor in the Employee constructor: 本质上与您只是从Employee构造函数中的Person构造函数内部复制所有代码相同:

function Employee(id, name) {
    this.name = name; //copied from Person
    this.id = id;
}

This results in the following setup and an employee with a name property: 这将导致以下设置以及具有name属性的员工:

|Person|                       |Employee|
|------|                       |--------|
|name  |                       |wage    |
|sex   |                       |id      |
                               |name    |
                               |sex     |

   |                               |
   |                               |
   v                               v

|Person Prototype|             |Employee Prototype|
|----------------|             |------------------|
|walk()          |  <--------  |work()            |
|eat()           |             |goOnStrike()      |
|sleep()         |

   |
   |
   v

|Object|
|------|
| ***  |

Not calling the super's constructor implies that the subclass has some knowledge of the superclass's behavior: that's the opposite of encapsulation. 不调用父类的构造函数意味着子类对父类的行为有所了解:这与封装相反。 It shouldn't know if the parent class needs or doesn't need any kind of 'setup' in its constructor. 它不应该知道父类在其构造函数中是否需要任何“设置”。 To be safe, it should simply call it and carry on. 为了安全起见,它应该简单地调用它并继续。

For example, if Person always had to initialize a bunch of properties on instantiation, and Employee didn't call Person constructor, Employee instance operations that rely on Person properties/methods may not behave properly. 例如,如果Person始终必须在实例化时初始化一堆属性,而Employee 没有调用Person构造函数,则依赖于Person属性/方法的Employee实例操作可能无法正常运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM