【问题标题】:Overriding methods in JavaScript with constructor property使用构造函数属性覆盖 JavaScript 中的方法
【发布时间】:2013-04-19 13:23:32
【问题描述】:

这是一种在 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

【问题讨论】:

  • JavaScript 中不存在“方法重载”之类的东西。在这种情况下,我认为您的意思是“覆盖”,但是 JS 中也没有这样的东西。
  • 对不起,错字:覆盖

标签: javascript


【解决方案1】:

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

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

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

如果你调用sayHi 而不使用callapplythis 将在函数调用期间指向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 来展示这个概念。

【讨论】:

    【解决方案2】:

    没有。

    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);
    

    【讨论】:

      猜你喜欢
      • 2014-06-09
      • 1970-01-01
      • 2013-03-22
      • 2013-03-01
      • 1970-01-01
      • 2016-07-21
      • 1970-01-01
      • 1970-01-01
      • 2014-05-22
      相关资源
      最近更新 更多