Дэвид Флэнаган - JavaScript. Подробное руководство, 6-е издание
- Название:JavaScript. Подробное руководство, 6-е издание
- Автор:
- Жанр:
- Издательство:Символ-Плюс
- Год:2012
- Город:СПб
- ISBN:978-5-93286-215-5
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Дэвид Флэнаган - JavaScript. Подробное руководство, 6-е издание краткое содержание
Эта книга - одновременно и руководство программиста, и полноценный справочник по базовому языку JavaScript и клиентским прикладным интерфейсам, предоставляемым веб-броузерами.
JavaScript. Подробное руководство, 6-е издание - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Еще одно важное отличие между примерами 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 определяет класс
Эти взаимосвязи между функцией-конструктором, ее прототипом, обратной ссылкой из прототипа на конструктор и экземплярами, созданными с помощью конструктора, иллюстрируются на рис. 9.1.
Обратите внимание, что в качестве примера для рис. 9.1 был взят наш конструктор Range().
Однако в действительности класс Range
, определенный в примере 9.2, замещает предопределенный объект Range.prototype
своим собственным. А новый объект-прототип не имеет свойства constructor
. По этой причине экземпляры класса Range
, как следует из определения, не имеют свойства constructor
. Решить эту проблему можно, явно добавив конструктор в прототип:
Range.prototype = {
constructor: Range, // Явно установить обратную ссылку на конструктор
includes: function(x) { return this.from <= x && x <= this.to; },
foreach: function(f) {
for(var x = Math.ceil(this.from); x <= this.to; x++) f(x);
},
toString: function() { return "(" + this.from + “..." + this.to + }
};
Другой типичный способ заключается в том, чтобы использовать предопределенный объект-прототип, который уже имеет свойство constructor, и добавлять методы в него:
// Здесь расширяется предопределенный объект Range.prototype,
// поэтому не требуется переопределять значение автоматически
// создаваемого свойства Range.prototype.constructor.
Range.prototype.includes = function(x) { return this.from<=x && x<=this.to; };
Range.prototype.foreach = function(f) {
for(var x = Math.ceil(this.from); x <= this.to; x++) f(x);
};
Range.prototype.toString = function() {
return "(" + this, from + "..." + this, to + ")";
};
9.3. Классы в стиле Java
Если вам приходилось программировать на языке Java или других объектно-ориентированных языках со строгим контролем типов, вы, возможно, привыкли считать, что классы могут иметь четыре типа членов:
Поля экземпляра
Это свойства, или переменные экземпляра, хранящие информацию о конкретном объекте.
Методы экземпляров
Методы, общие для всех экземпляров класса, которые вызываются относительно конкретного объекта.
Поля класса
Это свойства, или переменные, всего класса в целом, а не конкретного экземпляра.
Методы класса
Методы всего класса в целом, а не конкретного экземпляра.
Одна из особенностей языка JavaScript, отличающая его от языка Java, состоит в том, что функции в JavaScript являются значениями, и поэтому нет четкой границы между методами и полями. Если значением свойства является функция, это свойство определяется как метод. В противном случае это обычное свойство, или «поле». Но, несмотря на эти отличия, имеется возможность имитировать все четыре категории членов классов в языке JavaScript. Определение любого класса в языке JavaScript вовлекает три различных объекта (рис. 9.1), а свойства этих трех объектов действуют подобно различным категориям членов класса:
Читать дальшеИнтервал:
Закладка: