用构造函数属性覆盖JavaScript中的方法

时间:2013-04-19 13:23:33

标签: javascript

这是一种在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是crossbrowser,因为我可以使用垫片

2 个答案:

答案 0 :(得分: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);

答案 1 :(得分:1)

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

prototype

还有一些其他方法可以安全地访问父函数,比如直接引用Employee.prototype = Object.create(Person.prototype); Employee.prototype.constructor = Employee; 原型,就像你在第二个例子中试图做的那样,但是你做这件事的方式有问题。 / p>

如果您在未使用parentsayHi的情况下致电callapply会在功能调用期间指向this,这不是您想要的。 您应该通过将上下文对象设置为当前员工实例来调用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; }; 来调用功能。但是我不推荐这种解决方案,因为它会降低性能并增加内存使用量。

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