Метод переопределения класса Javascript - PullRequest
0 голосов
/ 08 сентября 2018

У меня есть этот класс

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) не переопределяют методы, унаследованные в конструкторе. Я знаю, что это можно было спросить раньше, но я не могу найти это извините.

1 Ответ

0 голосов
/ 09 сентября 2018

В комментариях @Bergi сделал предположение, что вы можете создавать экземпляры новых объектов MyClass во время выполнения и ссылаться на них. Поскольку вы пытаетесь изменить метод экземпляра объекта MyClass, а не его прототипа, все новые экземпляры MyClass (создаваемые с ключевым словом "new") по-прежнему будут наследовать свойства исходного MyClass.

Например, рассмотрим класс Fruit

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

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

и функция f, которая принимает любой объект и изменяет его свойство cutIntoPieces, устанавливая для него функцию, которая безусловно возвращает ноль и больше ничего не делает:

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

Давайте немного поэкспериментируем с этим в узле 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, которое является функцией, которая безусловно возвращает ноль и не влияет на объект.

Чтобы переопределить метод cutIntoPieces во всех экземплярах объекта, нам нужно изменить его в их прототипе, который является Fruit:

> Object.getPrototypeOf(banana);
Fruit {}

Чтобы создать такую ​​функцию, которая берет прототип объекта и изменяет его свойство, так что все экземпляры этого объекта наследуют измененное свойство, нам нужно немного переделать нашу функцию f. Давайте объявим другую функцию и назовем ее g:

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

Здесь g переопределил метод cutIntoPieces любого объекта, чтобы сделать резку более эффективной. Теперь, если мы вызовем g с Fruit.prototype, он изменит метод 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] }

Поскольку мы назвали f на банане, banana.cutIntoPieces теперь не имеет отношения к Fruit.prototype.cutIntoPieces. В то время как у апельсина и папайи этот метод унаследован от прототипа, у банана есть свой собственный:

> 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

Теперь банан, апельсин и папайя ведут себя одинаково.

Надеюсь, это поможет и удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...