簡體   English   中英

JavaScript類覆蓋方法

[英]Javascript class override method

我有這堂課

class MyClass {
    constructor(name, health, damage){
      INamable(this)
      IHealth(this)
      IDamage(this)
      IAttack(this)
      ITakeDamage(this)

      this.setName(name)
      this.setHealth(health)
      this.setDamage(damage)
    }

    attack(target){
        target.takeDamage(this.getDamage());
    }

    takeDamage(damage){
        this.setHealth(this.getHealth() - damage);
        if(this.getHealth()<=0){
            this.die();
        }
    }

    toString(){
        return "myClassToString"
    }
}

//一些接口(方法)

  function IAttack(object){
        let attack = function(){}
        object.attack = attack;
    }
    function ITakeDamage(object){
        let takeDamage = function(){}
        object.takeDamage = takeDamage;
    }

我的問題是,為什么attack(target)takeDamage(damage)不會覆蓋構造函數中繼承的方法。 我知道之前可能會問過這個問題,但我對此感到抱歉。

在注釋中,@ Bergi假定您可能正在運行時實例化新的MyClass對象並對其進行引用。 因為您嘗試更改MyClass對象實例的方法而不是其原型,所以MyClass的所有新實例(使用“ new”關鍵字創建)仍將繼承原始MyClass的屬性。

例如,考慮一個水果類

class Fruit {
  constructor() {
    this.pieces = 1;
  }

  cutIntoPieces(pieces) {
    this.pieces = pieces;
    return this;
  }
}

一個函數f ,它接受任何對象並更改其屬性cutIntoPieces ,將其設置為一個無條件返回null cutIntoPieces執行其他任何操作的函數:

const f = object => {
  object.cutIntoPieces = () => null;
};

讓我們在Node REPL中嘗試一下:

> banana = new Fruit();
Fruit { pieces: 1 }
> orange = new Fruit();
Fruit { pieces: 1 }
> papaya = new Fruit();
Fruit { pieces: 1 }
> f(banana);
undefined
> banana.cutIntoPieces(2);
null
> banana
Fruit { pieces: 1, cutIntoPieces: [Function] }
> orange.cutIntoPieces(3);
Fruit { pieces: 3 }
> papaya.cutIntoPieces(4);
Fruit { pieces: 4 }

您可以看到,將香蕉切成薄片時,在香蕉上調用f改變其行為。 發生這種情況是因為現在香蕉具有自己的屬性 cutIntoPieces ,該函數無條件返回null且不影響對象。

要在對象的所有實例中重新定義方法cutIntoPieces ,我們需要在其原型(即Fruit)中對其進行更改:

> Object.getPrototypeOf(banana);
Fruit {}

為了使這樣一個函數,它的原型對象並改變它的屬性,因此該對象的所有實例繼承更改屬性,我們需要重新塑造我們的函數f了一下。 讓我們聲明另一個函數並將其命名為g

const g = object => {
  object.cutIntoPieces = function (cuts) {
    this.pieces = 2 ** cuts;
    return this;
  };
};

在此, g重新定義了任何對象的cutIntoPieces方法,以使切割效率更高。 現在,如果我們用Fruit.prototype調用g ,它將更改方法orange和番木瓜的cutIntoPieces

> g(Fruit.prototype);
undefined
> orange.cutIntoPieces(4);
Fruit { pieces: 16 }
> papaya.cutIntoPieces(10);
Fruit { pieces: 1024 }

那香蕉怎么了?

> banana.cutIntoPieces(2);
null
> banana
Fruit { pieces: 1, cutIntoPieces: [Function] }

因為我們在香蕉上調用了fbanana.cutIntoPieces現在與Fruit.prototype.cutIntoPieces不相關。 盡管Orange和木瓜具有從原型繼承的此方法,但是香蕉有其自己的:

> orange.cutIntoPieces === Fruit.prototype.cutIntoPieces
true
> papaya.cutIntoPieces === Fruit.prototype.cutIntoPieces
true
> banana.cutIntoPieces === Fruit.prototype.cutIntoPieces
false

我猜這很好。 如果只想更改一個實例的行為,則可以定義自己的屬性,自己的方法; 另一方面,當您需要更改所有具有從原型繼承的方法的實例的行為時,可以更改其原型。

但是如何將香蕉切成薄片后表現出與其他水果相同的效果? 讓我們刪除它自己的cutIntoPieces

> delete banana.cutIntoPieces
true
> banana
Fruit { pieces: 1 }
> banana.cutIntoPieces(2)
Fruit { pieces: 4 }

請參閱,在刪除對象自己的屬性后,如果有一個,則從原型繼承另一個同名的屬性:

> banana.cutIntoPieces === Fruit.prototype.cutIntoPieces
true

現在,香蕉,橙和木瓜的行為相同。

希望對您有幫助,並祝您好運!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM