1

这是在 JavaScript 中实现方法覆盖的好/安全的跨浏览器方式吗?:

function Person(firstName, lastName)
{
  this.firstName = firstName;
  this.lastName = lastName;
};

Person.prototype.sayHi = function()
{
  return "Hi, my name is " + this.firstName;
};

function Employee(firstName, lastName, position)
{
  Person.call(this, firstName, lastName);
  this.position = position;
};

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

Employee.prototype.sayHi = function()
{
  return this.constructor.prototype.sayHi() + " I'm a " + this.position;
}

我也可以写:

Employee.prototype.sayHi = function()
{
  return Person.prototype.sayHi() + " I'm a " + this.position;
}

但是对于这个解决方案,我指的是直接方法,或者

Employee.prototype.sayHi = function()
{
  return this.__proto__.sayHi() + " I'm a " + this.position;
}

但这一个很糟糕,而且不是跨浏览器。

编辑:我假设 Object.create 是跨浏览器,因为我可以使用 shim

4

2 回答 2

1

不。

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

Object.create旧浏览器不支持,但您可以填充它。

Employee.prototype.sayHi = function() {
    return this.constructor.prototype.sayHi() + " I'm a " + this.position;
}

我不会用那个。您希望this.constructor成为Person您继承的对象,但情况可能并非如此。实际上,设置 是一个好习惯Employee.prototype.constructor = Employee,这会导致递归堆栈溢出到您的方法。

相反,您应该明确引用要使用的函数:

return Person.prototype.sayHi.call(this) + " I'm a " + this.position;

如果你想要它动态,你会使用

return Object.getPrototypeOf(Employee.prototype).sayHi.call(this) + " I'm a " + this.position;

但请注意,Object.getPrototypeOf旧浏览器不支持此功能。因此,如果您需要跨浏览器和 DRY 方式,请使用模块模式:

(function(proto, super) {
     proto.sayHi = function() {
         return super.sayHi.call(this) + " I'm a " + this.position;
     };
     …
})(Employee.prototype, Person.prototype);

或揭示原型模式:

Employee.prototype = (function(super) {
     var proto = Object.create(super);
     proto.sayHi = function() {
         return super.sayHi.call(this) + " I'm a " + this.position;
     };
     …
     return proto;
})(Person.prototype);
于 2013-04-19T13:34:09.517 回答
1

您不应依赖 的constructor属性prototype来调用父函数,因为通常该属性应指向子构造函数。

Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;

还有一些其他方法可以安全地访问父函数,例如parent直接引用原型,就像您在第二个示例中尝试做的那样,但是您的操作方式有问题。

如果您在sayHi不使用callor的情况下调用applythis将在函数调用期间指向Person.prototype,这不是您想要的。您应该sayHi通过将上下文对象设置为当前员工实例来调用,如下所示:

Employee.prototype.sayHi = function() {
  return Person.prototype.sayHi.call(this) + " I'm a " + this.position;
};

另一种方法是在子原型中存储对父原型的引用。

 Employee.prototype.super = Person.prototoype;

 Employee.prototype.sayHi = function() {
    return this.super.sayHi.call(this) + " I'm a " + this.position;
 };

我见过的另一种有趣的方法是将子原型的每个函数包装在一个函数中,该函数动态设置对对象实例上父函数的引用,这样您就只能this.parent()用来调用该函数。但是我不推荐这种解决方案,因为它会降低性能并增加内存使用量。

我创建了一个jsFiddle来演示这个概念。

于 2013-04-19T13:35:27.743 回答