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

What's the need for call() in prototypical 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()服务于"complete the object build"。但是, type 属性 不需要 call() 就可以在Manager中得到反映,这证明我们不需要硬对象来执行继承(我的意思是,只是class-like 构造函数定义即可)。

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

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

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

属性 type 自您完成原型界面以来一直有效。

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

即使原型是继承的,它是定义类型 'human' 的地方,但如果不调用 Employee,您就不会 "initializing the base class" 和 运行ning 内部的代码Employee() 构造函数。仅仅因为 Employee 是 Manager 的原型并不能保证您在创建经理时想要 运行 Employee 构造函数。

与可以调用 super() 的某些语言不同,您必须按名称调用基础 class 的初始化程序。这类似于 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');

.type(以及其他原型继承的属性)确实有效,是的。
但是 .name.dept 没有,它们不是在 m 上创建的!你说得很对,Employee.call(this) 完整初始化 所必需的。是构造函数的super调用,不能省略。