JavaScript. Подробное руководство, 6-е издание, стр. 121

JavaScript. Подробное руководство, 6-е издание - i_012.jpg

Класс

<b>Card</b>
в примере 9.8 определяет подобный метод
<b>compareTo(),</b>
и мы можем написать похожий метод для класса
<b>Range</b>
, чтобы упорядочивать диапазоны по их нижним границам:

<b>Range.prototype.compareTo = function(that) { </b>

<b>  return this.from - that.from;</b>

<b>};</b>

Обратите внимание, что вычитание, выполняемое этим методом, возвращает значение меньше нуля, равное нулю или больше нуля в соответствии с порядком следования двух объектов

<b>Range</b>
. Поскольку перечисление
<b>Card.Rank</b>
в примере 9.8 имеет метод
<b>valueOf(),</b>
мы могли бы использовать тот же прием и в методе
<b>сотраreTo()</b>
класса
<b>Card</b>
.

Методы

<b>equals(),</b>
представленные выше, выполняют проверку типов своих аргументов и возвращают
<b>false</b>
, как признак неравенства, если аргументы имеют не тот тип. Метод
<b>compareTo()</b>
не имеет специального возвращаемого значения, с помощью которого можно было бы определить, что «эти два значения не могут сравниваться», поэтому обычно методы
<b>compareTo()</b>
возбуждают исключение при передаче им аргументов неверного типа.

Примечательно, что метод

<b>compareTo()</b>
класса
<b>Range</b>
, представленный выше, возвращает 0, когда два диапазона имеют одинаковые нижние границы. Это означает, что в данной реализации метод
<b>сотрагеТо()</b>
считает равными любые два диапазона, которые имеют одинаковые нижние границы. Однако такое определение равенства не согласуется с определением, положенным в основу метода
<b>equals(),</b>
который требует равенства обеих границ. Подобные несоответствия в определениях равенства могут стать причиной опасных ошибок, и было бы лучше привести методы
<b>equals()</b>
и
<b>compareTo()</b>
в соответствие друг с другом. Ниже приводится обновленная версия метода
<b>compareTo()</b>
класса
<b>Range</b>
. Он соответствует методу
<b>equals()</b>
и дополнительно возбуждает исключение при передаче ему несопоставимого значения:

<b>// Порядок следования диапазонов определяется их нижними границами</b>

<b>// или верхними границами, если нижние границы равны.Возбуждает исключение,</b>

<b>// если методу передается объект, не являющийся экземпляром класса Range.</b>

<b>// Возвращает 0, только если this.equals(that) возвращает true.</b>

<b>Range.prototype.compareTo = function(that) {</b>

<b>  if (!(that instanceof Range))</b>

<b>    throw new Еrror(&quot;Нельзя сравнить Range c &quot; + that);</b>

<b>  var diff = this.from - that.from; // Сравнить нижние границы</b>

<b>  if (diff == 0) diff = this.to - that.to; // Если равны, сравнить верхние </b>

<b>  return diff;</b>

<b>};</b>

Одна из причин, по которым может потребоваться сравнивать экземпляры класса, - обеспечить возможность сортировки массива экземпляров этого класса. Метод Array.sort() может принимать в виде необязательного аргумента функцию сравнения, которая должна следовать тем же соглашениям о возвращаемом значении, что и метод

<b>compareTo().</b>
При наличии метода
<b>compareTo(),</b>
представленного выше, достаточно просто организовать сортировку массива объектов
<b>Range</b>
, как показано ниже:

<b>ranges.sort(function(a,b) { return a.compareTo(b); });</b>

Сортировка имеет настолько большое значение, что следует рассмотреть возможность реализации статического метода сравнения в любом классе, где определен метод экземпляров

<b>compareTo().</b>
Особенно если учесть, что первый может быть легко реализован в терминах второго, например:

<b>Range.byLowerBound = function(a,b) { return a.compareTo(b); };</b>

При наличии этого метода сортировка массива может быть реализована еще проще:

<b>ranges.sort(Range.byLowerBound);</b>

Некоторые классы могут быть упорядочены более чем одним способом. Например, класс

<b>Card</b>
определяет один метод класса, упорядочивающий карты по масти, а другой - упорядочивающий по значению.

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

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

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

<b>Set</b>
, например, когда скопировали метод
<b>toArray()</b>
и заставили его играть вторую роль в виде метода
<b>toJSON()</b>
.

Одна и та же функция может даже использоваться как метод сразу нескольких классов. Большинство методов класса

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