JS 中的继承:this.base = Class();this.base() 还是 ...?

Inheritance in JS: this.base = Class(); this.base() or ...?

提问人:Merc 提问时间:7/5/2011 更新时间:6/23/2018 访问量:8329

问:

我正在尝试在 JS 中“获取”继承。 我刚刚发现了一种巧妙的方法,基本上可以将所有属性从一个对象复制到另一个对象:

function Person(name){
  this.name="Mr or Miss: "+name;

  this.introduce = function(){
    console.log("Hi, I am "+this.name);
  }
}

function Employee(name,title){
  this.title=title;

  this.base=Person;
  this.base(name);  

}

e = new Employee('tony', 'manager')
e.introduce();

请注意,我有一个带有构造函数的 Person() 类,其属性“name”由构造函数生成。 这样做的好处还在于,员工在构造函数中也有名称——瞧,它使用相同的参数创建 Person 对象。

如果我用“原型”方式做到这一点:

function Person(name){

  this.introduce = function(){
    console.log("Hi, I am "+this.name);
  }
}

function Employee(name, title){
  this.name = name; /*  ?!?!?!?!? I can't call the proper constructor here */
  this.title = title;
}
Employee.prototype= new Person(); /* ?!?!? NO NAME HERE..>? */
Employee.prototype.constructor = Employee;


e = new Employee('tony', 'manager')
e.introduce();

犯 错。。。。现在怎么办?我什至无法完成这个:无法使用正确的 Person 构造函数设置 Employee 中的 this.name;Person 对象的创建在继承中仅发生一次。

所以。。。我错过了什么?在我的情况下,我给出的第一个例子是“那个”方法吗?有没有办法与第二个例子产生相同的结果?

帮助!

JavaScript 继承

评论


答:

12赞 Felix Kling 7/5/2011 #1

这种原型继承通常是这样完成的:

function Parent() {}

function Child() {
    Parent.call(this); // call the constructor of the parent
}

var Constr = function() {};
Constr.prototype = Parent.prototype;

Child.prototype = new Constr();
Child.prototype.constructor = Child;

所以“诀窍”是将 as 原型分配给一个空函数,并将这个函数的新实例设置为 的原型。Parent.prototypeChild

这样做是为了让扩展不会扩展。Child.prototypeParent.prototype

您还必须在子级的构造函数中调用父级的构造函数。我想这是你挣扎的部分。每个函数都有一个调用 [docs] 和 apply [docs] 方法,让你显式设置元素应该在函数中引用。this

在您的示例中,它看起来像:

function Employee(name,title){
  this.title=title;

  Person.call(this, name);
}

而不将构造函数分配给实例的属性。

在您的示例中,有效,因为通过将构造函数分配给实例的属性(并以这种方式调用它),函数内部引用了该实例。this.base(name)this


有几个库实现了这种模式,例如 Google Closure 库

goog.inherits = function(childCtor, parentCtor) {
  /** @constructor */
  function tempCtor() {};
  tempCtor.prototype = parentCtor.prototype;
  childCtor.superClass_ = parentCtor.prototype;
  childCtor.prototype = new tempCtor();
  childCtor.prototype.constructor = childCtor;
}; 

评论

0赞 Merc 7/5/2011
我完全理解 Google Closure 库中的功能(哇,我一定在某个地方:D)但!据我了解,当我创建派生类时,是否要继承内部属性取决于我,键入 Parent.call(this);或者 Parent.call(this, name) -- 是这样吗?你不是一直想这样做吗,真的吗?
0赞 Felix Kling 7/5/2011
@Tony:我想你会的。但是,如果你考虑了经典继承(如Java),那么如果你覆盖了它,你也必须调用父级的构造函数。唯一的区别是,在 JavaScript 中,你基本上总是覆盖构造函数,因为这是我们模拟类的方式。所以它实际上并没有那么不同,也许更容易理解正在发生的事情。