我在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()
那么重要,那就是)。
答案 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
调用,你不应该忽略它。