Дэвид Флэнаган - JavaScript. Подробное руководство, 6-е издание
- Название:JavaScript. Подробное руководство, 6-е издание
- Автор:
- Жанр:
- Издательство:Символ-Плюс
- Год:2012
- Город:СПб
- ISBN:978-5-93286-215-5
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Дэвид Флэнаган - JavaScript. Подробное руководство, 6-е издание краткое содержание
Эта книга - одновременно и руководство программиста, и полноценный справочник по базовому языку JavaScript и клиентским прикладным интерфейсам, предоставляемым веб-броузерами.
JavaScript. Подробное руководство, 6-е издание - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Метод compareTo()
должен принимать единственный аргумент и сравнивать его с объектом, метод которого был вызван. Если объект this
меньше, чем объект, представленный аргументом, метод compareTo()
должен возвращать значение меньше нуля. Если объект this
больше, чем объект, представленный аргументом, метод должен возвращать значение больше нуля. И если оба объекта равны, метод должен возвращать ноль. Эти соглашения о возвращаемом значении весьма важны, потому что позволяют выполнять замену операторов отношения следующими выражениями:
Класс Card
в примере 9.8 определяет подобный метод compareTo(),
и мы можем написать похожий метод для класса Range
, чтобы упорядочивать диапазоны по их нижним границам:
Range.prototype.compareTo = function(that) {
return this.from - that.from;
};
Обратите внимание, что вычитание, выполняемое этим методом, возвращает значение меньше нуля, равное нулю или больше нуля в соответствии с порядком следования двух объектов Range
. Поскольку перечисление Card.Rank
в примере 9.8 имеет метод valueOf(),
мы могли бы использовать тот же прием и в методе сотраreTo()
класса Card
.
Методы equals(),
представленные выше, выполняют проверку типов своих аргументов и возвращают false
, как признак неравенства, если аргументы имеют не тот тип. Метод compareTo()
не имеет специального возвращаемого значения, с помощью которого можно было бы определить, что «эти два значения не могут сравниваться», поэтому обычно методы compareTo()
возбуждают исключение при передаче им аргументов неверного типа.
Примечательно, что метод compareTo()
класса Range
, представленный выше, возвращает 0, когда два диапазона имеют одинаковые нижние границы. Это означает, что в данной реализации метод сотрагеТо()
считает равными любые два диапазона, которые имеют одинаковые нижние границы. Однако такое определение равенства не согласуется с определением, положенным в основу метода equals(),
который требует равенства обеих границ. Подобные несоответствия в определениях равенства могут стать причиной опасных ошибок, и было бы лучше привести методы equals()
и compareTo()
в соответствие друг с другом. Ниже приводится обновленная версия метода compareTo()
класса Range
. Он соответствует методу equals()
и дополнительно возбуждает исключение при передаче ему несопоставимого значения:
// Порядок следования диапазонов определяется их нижними границами
// или верхними границами, если нижние границы равны.Возбуждает исключение,
// если методу передается объект, не являющийся экземпляром класса Range.
// Возвращает 0, только если this.equals(that) возвращает true.
Range.prototype.compareTo = function(that) {
if (!(that instanceof Range))
throw new Еrror("Нельзя сравнить Range c " + that);
var diff = this.from - that.from; // Сравнить нижние границы
if (diff == 0) diff = this.to - that.to; // Если равны, сравнить верхние
return diff;
};
Одна из причин, по которым может потребоваться сравнивать экземпляры класса, - обеспечить возможность сортировки массива экземпляров этого класса. Метод Array.sort() может принимать в виде необязательного аргумента функцию сравнения, которая должна следовать тем же соглашениям о возвращаемом значении, что и метод compareTo().
При наличии метода compareTo(),
представленного выше, достаточно просто организовать сортировку массива объектов Range
, как показано ниже:
ranges.sort(function(a,b) { return a.compareTo(b); });
Сортировка имеет настолько большое значение, что следует рассмотреть возможность реализации статического метода сравнения в любом классе, где определен метод экземпляров compareTo().
Особенно если учесть, что первый может быть легко реализован в терминах второго, например:
Range.byLowerBound = function(a,b) { return a.compareTo(b); };
При наличии этого метода сортировка массива может быть реализована еще проще:
ranges.sort(Range.byLowerBound);
Некоторые классы могут быть упорядочены более чем одним способом. Например, класс Card
определяет один метод класса, упорядочивающий карты по масти, а другой - упорядочивающий по значению.
9.6.5. Заимствование методов
В методах 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).
Интервал:
Закладка: