Чтение онлайн

на главную - закладки

Жанры

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

// Возвращает строковое представление диапазона

toString: function { return "(" + this, from + "..." + this, to + ")"; }

};

// Ниже приводится пример использования объекта range.

var r = new Range(1.3); // Создать новый объект range

r.includes(2); // => true: число 2 входит в диапазон

r.foreach(console.log); // Выведет 1 2 3

console.log(r); // Выведет (1...3)

Имеет смысл детально сравнить примеры 9.1 и 9.2 и отметить различия между этими двумя способами определения классов. Во-первых, обратите внимание, что при преобразовании в конструктор фабричная функция

range
была переименована в
Range.
Это обычное соглашение по оформлению: функции-конструкторы в некотором смысле определяют классы, а имена классов начинаются с заглавных символов. Имена обычных функций и методов начинаются со строчных символов.

Далее отметьте, что конструктор

Range
вызывается (в конце примера) с ключевым словом
new
, тогда как фабричная функция
range
вызывается без него. В примере 9.1 для создания нового объекта использовался вызов обычной функции (раздел 8.2.1), а в примере 9.2 - вызов конструктора (раздел 8.2.3). Поскольку конструктор
Range
вызывается с ключевым словом
new
, отпадает необходимость вызывать функцию
inherit
или предпринимать какие-либо другие действия по созданию нового объекта. Новый объект создается автоматически перед вызовом конструктора и доступен в конструкторе как значение
this
. Конструктору
Range
остается лишь инициализировать его. Конструкторы даже не должны возвращать вновь созданный объект. Выражение вызова конструктора автоматически создает новый объект, вызывает конструктор как метод этого объекта и возвращает объект. Тот факт, что вызов конструктора настолько отличается от вызова обычной функции, является еще одной причиной, почему конструкторам принято давать имена, начинающиеся с заглавного символа. Конструкторы предназначены для вызова в виде конструкторов, с ключевым словом
new
, и обычно при вызове в виде обычных функций они не способны корректно выполнять свою работу. Соглашение по именованию конструкторов, обеспечивающее визуальное отличие имен конструкторов от имен обычных функций, помогает программистам не забывать использовать ключевое слово
new
.

Еще одно важное отличие между примерами 9.1 и 9.2 заключается в способе именования объекта-прототипа. В первом примере прототипом было свойство

range.methods
. Это было удобное, описательное имя, но в значительной мере произвольное. Во втором примере прототипом является свойство
Range.prototype
, и это имя является обязательным. Выражение вызова конструктора
Range
автоматически использует свойство
Range.prototype
как прототип нового объекта
Range
.

Наконец, обратите также внимание на одинаковые фрагменты примеров 9.1 и 9.2: в обоих классах методы объекта range определяются и вызываются одинаковым способом.

9.2.1. Конструкторы и идентификация класса

Как видите, объект-прототип играет чрезвычайно важную роль в идентификации класса: два объекта являются экземплярами одного класса, только если они наследуют один и тот же объект-прототип. Функция-конструктор, инициализирующая свойства нового объекта, не является определяющей: два конструктора могут иметь свойства

prototype
, ссылающиеся на один объект-прототип. В этом случае оба конструктора будут создавать экземпляры одного и того же класса.

Хотя конструкторы не играют такую же важную роль в идентификации класса, как прототипы, тем не менее конструкторы выступают в качестве фасада класса. Например, имя конструктора обычно используется в качестве имени класса. Так, принято говорить, что конструктор

Range
создает объекты класса
Range
. Однако более важным применением конструкторов является их использование в операторе
instanceof
при проверке принадлежности объекта классу. Если имеется объект r, и необходимо проверить, является ли он объектом класса
Range
, такую проверку можно выполнить так:

r instanceof Range // вернет true, если r наследует Range.prototype

В действительности оператор

instanceof
не проверяет, был ли объект r инициализирован конструктором
Range
. Он проверяет, наследует ли этот объект свойство
Range.prototype
. Как бы то ни было, синтаксис оператора
instanceof
закрепляет использование конструкторов в качестве идентификаторов классов. Мы еще встретимся с оператором
instanceof
далее в этой главе.

9.2.2. Свойство constructor

В примере 9.2 свойству

Range.prototype
присваивался новый объект, содержащий методы класса. Хотя было удобно определить методы как свойства единственного объекта-литерала, но при этом совершенно не было необходимости создавать новый объект. Роль конструктора в языке JavaScript может играть любая функция, поскольку выражению вызова конструктора необходимо лишь свойство
рrototype
. Следовательно, любая функция (кроме функций, возвращаемых методом
Function.bind
в ECMAScript 5) автоматически получает свойство
prototype
. Значением этого свойства является объект, который имеет единственное неперечислимое свойство
constructor
. Значением свойства
constructor
является объект функции:

var F = function {};
// Это объект функции.

var р = F.prototype;
// Это объект-прототип, связанный с ней.

var c = p.constructor;
// Это функция, связанная с прототипом.

c === F
// => true: F.prototype.constructor === F для всех функций

Наличие предопределенного объекта-прототипа со свойством

constructor
означает, что объекты обычно наследуют свойство
constructor
, которое ссылается на их конструкторы. Поскольку конструкторы играют роль идентификаторов классов, свойство
constructor
определяет класс объекта:

var о = new F; // Создать объект класса F

о.constructor === F // => true: свойство constructor определяет класс

Поделиться:
Популярные книги

Эволюционер из трущоб. Том 5

Панарин Антон
5. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 5

Вернувшийся: Корпорация. Том III

Vector
3. Вернувшийся
Фантастика:
космическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Вернувшийся: Корпорация. Том III

Сильнейший Столп Империи. Книга 1

Ермоленков Алексей
1. Сильнейший Столп Империи
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Сильнейший Столп Империи. Книга 1

Сердце Дракона. Том 9

Клеванский Кирилл Сергеевич
9. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
7.69
рейтинг книги
Сердце Дракона. Том 9

Агенты ВКС

Вайс Александр
3. Фронтир
Фантастика:
боевая фантастика
космическая фантастика
5.00
рейтинг книги
Агенты ВКС

Телохранитель Генсека. Том 1

Алмазный Петр
1. Медведев
Фантастика:
попаданцы
альтернативная история
7.00
рейтинг книги
Телохранитель Генсека. Том 1

Лекарь Империи 8

Лиманский Александр
8. Лекарь Империи
Фантастика:
попаданцы
городское фэнтези
аниме
5.00
рейтинг книги
Лекарь Империи 8

Мастер 4

Чащин Валерий
4. Мастер
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Мастер 4

Лейтенант. Назад в СССР. Книга 8. Часть 1

Гаусс Максим
8. Второй шанс
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Лейтенант. Назад в СССР. Книга 8. Часть 1

Хроники Тириса. Книга 1

Маханенко Василий Михайлович
1. Хроники Тириса
Фантастика:
боевая фантастика
космическая фантастика
фантастика: прочее
6.00
рейтинг книги
Хроники Тириса. Книга 1

Идеальный мир для Лекаря 26

Сапфир Олег
26. Лекарь
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 26

Первый удар (сборник)

Уланов Андрей Андреевич
Фантастика:
научная фантастика
5.71
рейтинг книги
Первый удар (сборник)

Контртеррор

Валериев Игорь
6. Ермак
Фантастика:
альтернативная история
5.00
рейтинг книги
Контртеррор

Виктор Глухов агент Ада. Компиляция. Книги 1-15

Сухинин Владимир Александрович
Виктор Глухов агент Ада
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Виктор Глухов агент Ада. Компиляция. Книги 1-15