9.6.5. Заимствование методов

We use cookies. Read the Privacy and Cookie Policy

В методах JavaScript нет ничего необычного - это обычные функции, присвоенные свойствам объекта и вызываемые «посредством» или «в контексте» объекта.

Одна и та же функция может быть присвоена двум свойствам и играть роль двух методов. Мы использовали эту возможность в нашем классе Set, например, когда скопировали метод toArray() и заставили его играть вторую роль в виде метода toJSON().

Одна и та же функция может даже использоваться как метод сразу нескольких классов. Большинство методов класса Array, например, являются достаточно универсальными, чтобы копировать их из Array.prototype в прототип своего класса, экземпляры которого являются объектами, подобными массивам. Если вы смотрите на язык JavaScript через призму классических объектно-ориентированных языков, тогда использование методов одного класса в качестве методов другого класса можно рассматривать как разновидность множественного наследования. Однако JavaScript не является классическим объектно-ориентированным языком, поэтому я предпочитаю обозначать такой прием повторного использования методов неофициальным термином заимствование.

Заимствоваться могут не только методы класса Array: мы можем реализовать собственные универсальные методы. В примере 9.9 определяются обобщенные методы toString() и equals(), которые с успехом могут использоваться в таких классах, как Range, Complex и Card. Если бы класс Range не имел собственного метода equals(), мы могли бы заимствовать обобщенный метод equals(), как показано ниже:

Range.prototype.equals = generic.equals;

Обратите внимание, что метод generic.equals() выполняет лишь поверхностное сравнение и не подходит для использования в классах, свойства экземпляров которых ссылаются на объекты с их собственными методами equals(). Отметьте также, что этот метод включает специальный случай для обработки свойства, добавляемого к объектам при включении их в множество Set (пример 9.6).

Пример 9.9. Обобщенные методы, пригодные для заимствования

var generic = {

  // Возвращает строку, включающую имя функции-конструктора, если доступно,

  // и имена и значения всех неунаследованных свойств, не являющихся функциями.

  toString: function() {

    var s = '[';

    // Если объект имеет конструктор и конструктор имеет имя, использовать

    // это имя класса как часть возвращаемой строки. Обратите внимание, что

    // свойство name функций является нестандартным и не поддерживается повсеместно,

    if (this.constructor && this.constructor.name) s += this.constructor.name + ";

    // Теперь обойти все неунаследованные свойства, не являющиеся функциями

    var n = 0;

    for(var name in this) {

      if (!this.hasOwnProperty(name)) continue; // пропустить унаслед.

      var value = this[name];

      if (typeof value === ’function") continue; // пропустить методы

      if (n++) s += ", ";

      s += name + '=' + value;

    }

    return s + ']';

  },

  // Проверить равенство, сравнив конструкторы и свойства экземпляров объектов this

  // и that. Работает только с классами, свойства экземпляров которых являются

  // простыми значениями и могут сравниваться с помощью оператора ===.

  // Игнорировать специальное свойство, добавляемое классом Set.

  equals: function(that) {

    if (that == null) return false;

    if (this.constructor !== that.constructor) return false;

    for(var name in this) {

      if (name === "|**objectid**|") continue; // пропустить спец. св.

      if (!this.hasOwnProperty(name)) continue; // пропустить унасл. св.

      if (this[name] !== that[name]) return false; // сравнить значения

    }

    return true; // Объекты равны, если все свойства равны.

  }

};