在JavaScript中只覆盖一个实例的覆盖方法

时间:2016-12-19 14:02:55

标签: javascript oop inheritance override prototype

在我的项目中,我使用JavaScript原型来实现继承。我有一个超级类型(如汽车)和许多子类型(奥迪/梅赛德斯/ ...)。每个汽车品牌都在使用' Horn'这是一个非常庞大的类型,不应该重复。这种类型的一种方法应该被每个汽车品牌覆盖,但应该只存在于特定子类型的范围内。如果不为每个汽车子类型创建一个Horn子类型,这是否可行? 谢谢!

http://codepen.io/trek7/pen/QGYaBW

function Horn() {
  this.level = '123dB';
}

Horn.prototype.doTutut = function() {
  return "Düdelüüüü!";
};

/********************************************/

function Car() {
  this.horn = new Horn();
}

Car.prototype.honk = function() {
  return this.horn.doTutut();
};

/********************************************/

Mercedes.prototype = new Car();

function Mercedes() {
  this.color = 'blue';
}

Mercedes.prototype.drive = function() {
  return "...BrumBrum...";
};

/********************************************/

Audi.prototype = new Car();

function Audi() {
  this.color = 'red';

  /* BAD Overwrite, but how can I achieve this functionality
   without creating another Horn subtype? */
  Horn.prototype.doTutut = function() {
    return "Tütütütütü!";
  };
}

Audi.prototype.honk = function() {
  return this.horn.doTutut();
};

/********************************************/

var car = new Car();      
car.honk();  // Düdelüüüü! - Right!

var mercedes = new Mercedes();      
mercedes.honk();  // Düdelüüüü! - Right!

var audi = new Audi();      
audi.honk();  // Tütütütütü! - Right!

mercedes.honk();  // Tütütütütü! - Wrong!

1 个答案:

答案 0 :(得分:1)

这里常见的事情是参数化 Horn类,以便它接受要发出的声音:

function Horn(sound) {
  this.sound = sound !== undefined ? sound : "Düdelüüüü!";
  this.level = '123dB';
}

Horn.prototype.doTutut = function() {
  return this.sound;
};

然后在Mercedes内,你要么将声音传递给Car超级构造函数,要么在this.horn之后设置它。

如果您需要重写整个方法,可以将其分配给this.horn.theMethod

function Mercedes() {
  Car.call(this); // See below, important to do this first
  this.horn.theMethod = function() {
    // New implementation here
  };
}

...但是首先修复下面的继承内容非常重要。

当然,如果您希望所有Mercedes个实例(例如)共享单个 Horn实例,只需在{{1 }}

旁注:您的继承设置使用了经常重复的反模式。不要这样做:

Mercedes.prototype

如果你这样做,有两个问题:

  1. Mercedes.prototype = new Car(); 无法接受参数,

  2. Car错误

  3. 因为Mercedes.prototype.constructor对象Car)分配给new Horn,所以每个子类的所有实例(this,{ {1}}等)最终共享相同的对象(一个号角)。如果那个对象是无状态的,那很好,但它应该在Mercedes上。如果它不是无状态的,则会在Audi个实例之间产生难以诊断的串扰。

  4. 此外,Car.prototype永远不会调用Car,它应该为Mercedes提供初始化实例部分的机会。

    在ES5中,这是正确的方法:

    Car

    当然,在ES2015及以上版本中(您现在可以使用它进行转换),它只是:

    Car

    ...除非function Mercedes() { // Gives `Car` its chance to do init; could pass on args here if appropriate Car.call(this); this.color = 'blue'; } // Set up the prototype chain Mercedes.prototype = Object.create(Car.prototype); Mercedes.prototype.constructor = Mercedes; Mercedes.prototype.drive = function() { return "...BrumBrum..."; }; 构造函数接受参数class Mercedes extends Car { drive() { return "...BrumBrum..."; } } 不需要/使用。

    这是一个更新的继承和跨所有子类实例的共享号角的示例:

    Mercedes