什么是原型继承中call()的需要

时间:2015-07-03 11:28:24

标签: javascript prototypal-inheritance

我在JavaScript中破解原型继承时遇到了一些麻烦,并考虑在此处发布。考虑这个简单的例子:

function Employee() {
    this.name = "Rob";
    this.dept = "R&D";
}

function Manager() {
    //Employee.call(this);
    this.reports = ["Report 1", "Report 2", "Report 3"];
}

Manager.prototype = Object.create(Employee.prototype);

Employee.prototype.type = "human";
m = new Manager();
console.log(m.name); //undefined
console.log(m.type); //human

我无法理解的是行Employee.call(this)的效用。既然我们要将Employee.protoype设置为Manager的原型,那么(我认为)明确迫使通过call()在Employee中创建变量的需求是什么?之前我认为可能是因为Employee没有对象存在,并且JS继承无法在没有对象的情况下工作,所以call()在这里服务于"完成对象构建" 。但是,type属性在Manager中反映出来而不需要call(),这证明我们不需要硬对象来执行继承(我的意思是,只是类 - 像构造函数定义那样)。

我希望我没有把它弄得太复杂。简而言之:为什么这里需要call(),为什么属性type在没有call()的情况下工作(如果call()那么重要,那就是)。

3 个答案:

答案 0 :(得分:2)

Employee.call(this)的目的是向Manager实例添加名称和部门属性。

call()的用法更符合惯例,它允许修改调用者(this)。

自您完成原型界面以来,属性type已经起作用。

如果取消注释Employee.call(this),则m.name将变为“Rob”。

答案 1 :(得分:1)

即使原型是继承的,也就是定义了'human'类型的地方,而没有调用Employee,你不是“初始化基类”并在Employee()构造函数中运行代码。仅仅因为Employee是Manager的原型并不能保证您在创建管理器时想要运行Employee构造函数。

与您可以调用super()的某些语言不同,您必须按名称调用基类的初始值设定项。这类似于C ++:

class Manager : public Employee {
public:
    Manager() : Employee() {}
};

您还可以决定何时调用父级并执行其他逻辑,其中自动调用不会为您提供该选项:

function Employee(name) {
    this.name = name;
    this.dept = "R&D";
}

function Manager(name) {
    // Add the title to the name, first
    var mgrName = name + ' (Manager)';

    Employee.call(this, mgrName);
    this.reports = ["Report 1", "Report 2", "Report 3"];
}

Manager.prototype = Object.create(Employee.prototype);
m = new Manager('Bill');

答案 2 :(得分:0)

.type(和其他原型继承的属性)确实有效。是的 但是.name.dept没有,它们不是在m上创建的!你是对的,完成初始化需要Employee.call(this) 。这是构造函数的super调用,你不应该忽略它。