Объекты. Экземпляры объектов
Итак, мы познакомились с типами данных, переменными, константами, операторами, простыми и сложными выражениями, функциями и массивами. Но это была, так сказать, присказка, а сказка будет впереди. Настала пора узнать о самых сложных структурах данных JavaScript — объектах.
Понятия объекта и экземпляра объекта
В начале этой главы мы познакомились с типами данных, определяющими саму природу данных и набор действий, которые можно выполнять с этими данными. Так, строковый тип определяет, что данные этого типа представляют собой строки — наборы символов, которые можно объединять и сравнивать с другими строками.
Это были так называемые простые типы данных. Сущность, относящаяся к такому типу, может хранить только одно значение.
Однако JavaScript предоставляет нам и сложные типы данных. Сущность такого типа может хранить сразу несколько значений. Один из примеров сложного типа данных — уже знакомые нам массивы.
Другой пример сложного типа данных — объекты. Объект — это сложная сущность, способная хранить сразу несколько значений разных типов. Для этого объект определяет набор своего рода внутренних переменных, называемых свойствами; такое свойство может хранить одну сущность, относящуюся к простому или сложному типу данных. Так, одно свойство объекта может хранить строки, другое — числа, третье — массивы.
А еще объект может содержать набор внутренних функций, называемых методами. Методы могут обрабатывать данные, хранящиеся в свойствах или полученные "из-вне", менять значения свойств и возвращать результат, как обычные функции.
Объект — это всего лишь тип данных. Сущности же, хранящие реальные данные и созданные на основе этого объекта, называются его экземплярами. Точно так же, как строка "JavaScript" — экземпляр строкового типа данных, хранящий реальную строку.
Экземпляры объектов имеют такую же природу, как и массивы. Сам экземпляр объекта находится где-то в памяти компьютера, а в переменной хранится ссылка на него. При присваивании ее значения другой переменной выполняется присваивание именно ссылки. Не забываем об этом.
Каждый объект должен иметь уникальное имя, по которому к нему можно обратиться, чтобы создать его экземпляр. К именам объектов предъявляют те же требования, что и к именам переменных и функций.
Объекты — невероятно мощное средство объединить данные (свойства) и средства их обработки (методы) воедино. Так, объект, представляющий абзац Web-страницы, объединяет параметры этого абзаца, хранящиеся в различных свойствах, и инструменты для манипуляции абзацем, предоставляемые соответствующими методами. Нам не придется "раскидывать" параметры абзаца по десяткам переменных и пользоваться для работы с ним массой отдельных функций — все это сведено в один объект.
Экземпляры одного объекта — отдельные сущности, не влияющие друг на друга. Мы можем работать с одним экземпляром объекта, а другие экземпляры того же самого объекта останутся неизменными. Так, мы можем изменить параметры одного абзаца, присвоив новые значения свойствам соответствующего экземпляра объекта, не затрагивая другие абзацы на этой же Web-странице.
Все объекты, доступные в Web-сценариях, можно разделить на три разновидности:
- предоставляемые самим языком JavaScript (встроенные объекты);
- предоставляемые Web-обозревателем (объекты Web-обозревателя);
- созданные нами или сторонним разработчиком на самом JavaScript (пользовательские объекты). В частности, популярные JavaScript-библиотеки, такие как Ext Core, создают множество пользовательских объектов.
С точки зрения Web-программиста все эти объекты одинаковы. И работа ними и их экземплярами выполняется сходным образом.
Получение экземпляра объекта
Но как нам получить экземпляр нужного объекта?
- Экземпляры многих объектов создаются самим языком JavaScript, Web-обозревателем или библиотеками сторонних разработчиков.
- Экземпляры некоторых объектов возвращаются функциями или методами других объектов.
- Мы можем создать экземпляр объекта сами, написав соответствующее выражение.
Давайте рассмотрим все эти случаи подробно.
Прежде всего, сам язык JavaScript предоставляет нам несколько экземпляров различных объектов. Они хранятся в особых переменных, также создаваемых самим языком.
ВНИМАНИЕ!
Вообще-то, в переменных хранятся ссылки на экземпляры объектов. Просто раньше мы договорились, что будем считать, будто в переменных хранятся сами экземпляры объектов, — так проще.
Так, переменная Math хранит экземпляр одноименного объекта, поддерживающего множество методов для выполнения математических и тригонометрических вычислений над числами:
var a = Math.sqrt(2);
Это выражение поместит в переменную a квадратный корень из 2. Метод sqrt объекта Math как раз вычисляет квадратный корень из числа, переданного ему в качестве единственного параметра.
А метод sin объекта Math вычисляет синус угла, заданного в радианах и переданного данному методу единственным параметром:
var b = Math.sin(0.1);
Как видим, мы просто используем переменную Math, созданную языком JavaScript, чтобы получить доступ к экземпляру объекта Math и его методам.
Web-обозреватель также предоставляет множество экземпляров объектов, представляющих текущую Web-страницу, различные ее элементы и сам Web-обозреватель. Так, Web-страницу представляет экземпляр объекта HTMLDocument, который хранится в переменной document, также созданной Web-обозревателем.
В частности, объект HTMLDocument поддерживает метод write, выводящий переданную ему в качестве единственного параметра строку в то место Web-страницы, где встретился вызов этого метода:
document.write("Привет, посетитель!");
И в этом случае мы просто используем переменную document, созданную Web-обозревателем, чтобы получить доступ к экземпляру объекта HTMLDocument и его методу write.
Сторонние библиотеки также создают множество экземпляров объектов сами. Так, библиотека Ext Core создает экземпляр объекта Ext, хранящийся в одноименной переменной:
var ceLinks = Ext.select("UL[id=navbar] > LI");
Здесь мы обратились к методу select объекта Ext. Данный метод возвращает массив экземпляров объектов Element, каждый из которых представляет элемент Web-страницы, удовлетворяющий переданному ему в качестве единственного параметра специальному селектору CSS. (Кстати, объект Element также определен библиотекой Ext Core.)
Идем далее. Ранее было сказано, что экземпляр объекта можно получить в качестве результата выполнения функции или метода. Вот типичный пример:
var elNavbar = Ext.get("navbar");
Метод get объекта Ext, созданного библиотекой Ext Core, возвращает экземпляр объекта Element, представляющий определенный элемент Web-страницы. В данном случае это будет элемент, значение атрибута тега ID которого равно "navbar" — именно такую строку мы передали методу get в качестве параметра.
Здесь мы также получили готовый экземпляр объекта, с которым сразу можем начать работу.
И, наконец, с помощью оператора создания экземпляра new мы можем создать экземпляр нужного нам объекта сами, явно:
new <имя объекта>([<список параметров, разделенных запятыми>])
Оператор new возвращает созданный экземпляр объекта. Его можно присвоить какой-либо переменной или свойству или передать в качестве параметра функции или методу.
Список параметров может как присутствовать, так и отсутствовать. Обычно он содержит значения, которые присваиваются свойствам экземпляра объекта при его создании.
Язык JavaScript предоставляет нам объект Date, хранящий значение даты и времени. Его экземпляры можно создать только явно, оператором new:
var dNow = new Date();
После выполнения этого выражения в переменной dNow окажется экземпляр объекта Date, хранящий сегодняшнюю дату и текущее время.
А вот выражение, которое поместит в переменную dNewYear экземпляр объекта Date, хранящий дату 31 декабря 2009 года и текущее время:
var dNewYear = new Date(2009, 12, 31);
Но какой способ получения экземпляра объекта в каком случае применять? Выбор зависит от объекта, экземпляр которого мы хотим получить.
- Экземпляры объектов Web-обозревателя, представляющие Web-страницу и сам Web-обозреватель, доступны через соответствующие переменные.
- Экземпляры объектов Web-обозревателя, представляющие различные элементы Web-страницы, получаются в результате выполнения особой функции или метода.
- Экземпляры всех объектов языка JavaScript, кроме Math, получаются явным созданием с помощью оператора new.
- Экземпляр объекта Math языка JavaScript доступен через одноименную переменную.
Это самые общие правила. А конкретные приемы получения нужного экземпляра объекта мы рассмотрим потом, когда начнем заниматься Web-программированием вплотную.
Работа с экземпляром объекта
Получив тем или иным способом экземпляр объекта, мы можем с ним работать: вызывать его методы и получать доступ к его свойствам.
Ранее мы уже познакомились с методами различных объектов и выяснили, как они вызываются. Для этого к переменной, хранящей экземпляр объекта, добавляется справа точка, а после нее записывается вызов метода. Метод — суть "собственная" функция объекта, и вызывается она так же (см. раздел, посвященный вызовам функций).
Пример:
var elNavbar = Ext.get("navbar");
Здесь мы вызвали метод get объекта Ext, экземпляр которого хранится в переменной Ext, передав данному методу параметр — строку "navbar". Как мы уже знаем, метод get ищет на Web-странице элемент, имеющий значение атрибута тега ID, которое совпадает с переданной ему в качестве параметра строкой. Возвращенный этим методом результат — экземпляр объекта Element, представляющего список navbar, — будет присвоен переменной elNavbar.
Пример:
var elParent = elNavbar.parent();
А здесь мы вызвали метод parent у экземпляра объекта Element, хранящегося в переменной elNavbar и полученного в предыдущем выражении. Возвращенный этим методом результат — экземпляр объекта Element, представляющего элемент Web-страницы, который является родителем списка navbar, — будет присвоен переменной elParent.
Если результат, возвращаемый каким-либо методом (назовем его методом 1), представляет собой объект, мы можем сразу вызвать метод у него (это будет метод 2). Для этого мы добавим справа от вызова метода 1 точку, после которой поставим вызов метода 2.
Пример:
elNavbar.parent().addClass("hovered");
Здесь мы сначала вызвали метод parent у экземпляра объекта Element, хранящегося в переменной elNavbar (метод 1). У полученного в результате вызова метода 1 результата — экземпляра объекта Element, представляющего элемент-родитель, — мы вызвали метод addClass (метод 2).
Такие цепочки последовательных вызовов методов, когда стоящий справа метод вызывается у экземпляра, возвращенного методом, стоящим слева, встречаются в JavaScript-коде очень часто.
Доступ к свойствам объекта выполняется аналогично. К переменной, хранящей экземпляр объекта, добавляется справа точка, а после нее записывается имя свойства.
Пример:
var sID = elParent.id;
В данном примере мы обратились к свойству id объекта Element, экземпляр которого хранится в переменной elParent. Это свойство хранит значение атрибута тега ID у соответствующего элемента Web-страницы.
Пример:
Ext.enableFx = false;
Здесь мы присвоили новое значение свойству enableFx объекта Ext, экземпляр которого хранится в переменной Ext.
Пример:
var sID = elNavbar.parent().id;
А здесь мы сначала получили родитель элемента Web-страницы, хранящегося в переменной elNavbar, после чего извлекли значение атрибута тега ID уже у полученного родителя.
Что ж, с объектами и их экземплярами, свойствами и методами мы познакомились. Теперь давайте кратко "пробежимся" по объектам, которые будем использовать при написании Web-сценариев. Рассмотрим только встроенные объекты JavaScript и объекты Web-обозревателя; пользовательским объектам, создаваемым библиотекой Ext Core, будет полностью посвящена глава 15.
Встроенные объекты языка JavaScript
Ранее мы познакомились со встроенным объектом Date, который предоставляется самим языком JavaScript и служит для хранения значений даты и времени:
var dNow = new Date();
Объект Date поддерживает ряд методов, позволяющих получать отдельные составляющие даты и времени и манипулировать ими. Так, метод getDate возвращает число, getMonth — номер месяца, а getFullYear — год. Все эти методы не принимают параметров, а возвращаемые ими результаты представляют собой числа.
Пример:
var sNow = dNow.getDate() + "." + dNow.getMonth() + "." + dNow.getFullYear();
Здесь мы объединяем в одну строку число, номер месяца и год, разделяя их точками. Таким образом мы получим значение даты в формате <число>.<месяц>.<год>.
При этом JavaScript сам выполняет неявное преобразование числовых величин в строки.
Объект String служит для хранения строк.
var s = "JavaScript";
Мы только что создали экземпляр объекта String, хранящий строку JavaScript.
Здесь мы столкнулись с одной особенностью JavaScript, отличающей его от других языков программирования. Все значения простых типов данных в нем на самом деле являются экземплярами соответствующих объектов. Так, строка — это фактически экземпляр объекта String.
Свойство length объекта String хранит длину строки в символах:
var l = s.length; var l = "JavaScript".length;
Эти выражения помещают в переменную l длину строки JavaScript.
Метод substr возвращает фрагмент строки заданной длины, начинающийся с указанного символа:
substr(<номер первого символа>[, <длина фрагмента>]);
Первым параметром передается номер первого символа, включаемого в возвращаемый фрагмент строки.
ВНИМАНИЕ!
В JavaScript символы в строках нумеруются, начиная с нуля.
Второй, необязательный, параметр задает длину возвращаемого фрагмента в символах. Если он опущен, возвращаемый фрагмент будет содержать все оставшиеся символы строки.
После выполнения Web-сценария
var s1 = s.substr(4); var s2 = s.substr(4, 2);
в переменной s1 окажется строка "Script", а в переменной s2 — строка "Sc".
Объект Number служит для хранения чисел, а объект Boolean — логических величин:
var n = 123; var b = false;
Числа и логические величины с точки зрения JavaScript также представляют собой экземпляры соответствующих объектов.
Объект Array служит для хранения массивов:
var a = [1, 2, 3, 4];
Он поддерживает единственное свойство length, возвращающее размер массива, т. е. число элементов в нем:
var l = a.length; var l = [1, 2, 3, 4].length;
Уже знакомый нам объект Math, единственный экземпляр которого создается самим JavaScript и хранится в переменной Math, представляет набор методов для выполнения математических и тригонометрических вычислений.
Мы не будем рассматривать здесь все встроенные объекты JavaScript и поддерживаемые ими свойства и методы. Это можно найти в любой книге по JavaScript-программированию.
Объект Object и использование его экземпляров
Но об одном встроенном объекте следует поговорить особо. Это объект Object, весьма специфический.
Экземпляры этого объекта обычно используются для хранения сложных структур данных, включающих произвольный набор свойств и методов. Один экземпляр объекта Object может иметь один набор свойств и методов, а другой экземпляр — совсем другой.
Экземпляры объекта Object создают с помощью особых выражений, называемых инициализаторами. Инициализатор чем-то похож на определение стиля (листинг 14.12).

После выполнения инициализатора JavaScript вернет нам готовый экземпляр объекта Object, который мы можем присвоить какой-либо переменной или использовать в качестве параметра функции или метода.
Пример:
var oConfig = { tag: "DIV", id: "cother", html: "Это прочие сведения." };
Здесь мы получили экземпляр объекта Object со свойствами tag, id и html, задали для этих свойств значения и сохранили получившийся экземпляр в переменной oConfig.
Пример:
var oConfig2 = { url: "pages/t_img.htm", success: function (response, opts){ var obj = Ext.decode(response.responseText); } };
А здесь мы создали экземпляр объекта Object со свойством url и методом success и сохранили получившийся экземпляр в переменной oConfig2. (Код последнего примера взят из документации по библиотеке Ext Core.)
Обратим внимание на два момента. Во-первых, функцию, реализующую метод success, мы объявили прямо в инициализаторе. Во-вторых, создание метода в данном случае — суть присваивание функции, которая реализует этот метод, свойству, имя которого станет именем метода. Следовательно, здесь тот же самый случай, что и с присваиванием функции переменной (см. раздел, посвященный функциям).
Экземпляры объекта Object в библиотеке Ext Core обычно служат для задания различных необязательных параметров и создаются как раз с помощью инициализаторов. Так что мы часто будем иметь с ними дело.
Объекты Web-обозревателя. Объектная модель документа DOM
Объекты, предоставляемые Web-обозревателем, делятся на две группы:
- объекты, представляющие Web-страницу и элементы, созданные с помощью разных тегов (абзац, заголовок, таблица, изображение и др.);
- объекты, представляющие сам Web-обозреватель.
Начнем с объектов первой группы.
Как мы уже знаем, саму Web-страницу представляет объект HTMLDocument. Единственный экземпляр данного объекта хранится в переменной document и представляет Web-страницу, открытую в текущем окне Web-обозревателя.
Отдельный элемент Web-страницы, независимо от тега, с помощью которого он создан, представляется объектом HTMLElement. На этом объекте основаны другие объекты, представляющие элементы Web-страницы, которые созданы на основе определенных тегов. Так, абзац представляется объектом HTMLParagraphElement, изображение — объектом HTMLImageElement, гиперссылка — объектом HTMLLinkElement, а таблица — объектом HTMLTableElement.
Для каждого элемента загруженной Web-страницы Web-обозреватель создает экземпляр соответствующего объекта. Например, для каждого абзаца создается экземпляр объекта HTMLParagraphElement, для каждого изображения — экземпляр объекта HTMLImageElement, для каждой гиперссылки — экземпляр объекта HTMLLinkElement, а для каждой таблицы — экземпляр объекта HTMLTableElement.
В результате в памяти компьютера создается структура взаимосвязанных экземпляров объектов, соответствующая структуре элементов Web-страницы. Она называется объектной моделью документа, или DOM (сокращение от Document Object Model — объектная модель документа).
Объект HTMLDocument поддерживает ряд методов для доступа к нужному элементу Web-страницы, в смысле — к представляющему его экземпляру соответствующего объекта. Обычно для уникальной идентификации элемента Web-страницы используется значение атрибута тега ID.
Объект HTMLElement поддерживает свойства и методы, общие для всех типов элементов Web-страницы. Они позволяют получить или задать значение какого-либо атрибута тега, привязать к нему стилевой класс, вставить в элемент Web-страницы другой элемент в качестве дочернего и пр. Объекты, созданные на основе HTMLElement, расширяют этот набор свойств и методов.
DOM является одним из основополагающих стандартов Интернета, разрабатывается и утверждается организацией W3C. Все Web-обозреватели обязаны ее поддерживать.
Что касается объектов второй группы, то их немного. Это, прежде всего, объект Window, представляющий окно Web-обозревателя и поддерживающий ряд свойств и методов, с помощью которых мы можем им управлять. Экземпляр этого объекта, представляющий текущее окно Web-обозревателя, хранится в переменной window. Кроме того, существует еще несколько объектов, представляющих Web-обо-зреватель, но они встречаются значительно реже.
К рассмотрению объектов Web-обозревателя мы вернемся в главе 15. А пока что закончим с ними.
Свойства и методы экземпляра объекта
Как мы уже знаем, объект определяет набор свойств и методов, которые затем станут "собственностью" всех его экземпляров. Иными словами, экземпляр объекта получит все свойства и методы, что объявлены в объекте, на основе которого он создан. Это так называемые свойства и методы объекта.
Однако язык JavaScript предоставляет возможность создать у экземпляра объекта сколько угодно свойств и методов, которые будут принадлежать только ему. Другие экземпляры того же объекта эти свойства и методы не получат.
Пример:
var dNow = new Date(); dNow.someProperty = 3;
Здесь мы создали у экземпляра объекта Date, хранящегося в переменной dNow, свойство someProperty и присвоили ему значение 3. Данное свойство будет принадлежать только этому экземпляру объекта Date.
Пример:
elNavbar.someMethod = function() { . . . };
Здесь мы добавили к экземпляру объекта Element библиотеки Ext Core, хранящемуся в переменной elNavbar, метод someMethod. Опять же, данный метод будет принадлежать только этому экземпляру объекта.
А в следующем примере мы добавили к созданному ранее конфигуратору oConfig свойство style и присвоили этому свойству строку с определением встроенного стиля:
oConfig.style = "color: red;";
Такие свойства и методы, принадлежащие только одному экземпляру объекта, называются свойствами и методами экземпляра.
В Web-программировании свойства и методы экземпляра позволяют связать какой-либо элемент Web-страницы с некоторыми данными, которые будут использованы далее в Web-сценарии применительно к этому элементу. В последующих главах мы рассмотрим такие случаи.
Правила написания выражений
В процессе чтения этой главы мы изучили множество выражений JavaScript. Но так и не узнали, по каким правилам они пишутся. Настала пора восполнить пробел в наших знаниях.
- Между операндами, операторами, вызовами функций и методов и ключевыми словами допускается сколько угодно пробелов и разрывов строк.
- Запрещаются переносы строк внутри константы, ключевого слова, имени переменной, свойства, функции, метода или объекта. В противном случае мы получим сообщение об ошибке.
- Признаком конца выражения служит символ точки с запятой (;).
В качестве примера давайте возьмем одно из выражений из начала главы:
y = y1 * y2 + x1 * x2;
Мы можем записать его так, разнеся на две строки:
y = y1 * y2 + x1 * x2;
Или даже так:
y = y1 * y2 + x1 * x2;
И в любом случае оно будет выполнено, т. к. при написании выражения мы не нарушили ни одного из перечисленных правил.
Но если мы нарушим их, выполнив перенос строк внутри имени переменной y2:
y = y1 * y 2 + x1 * x2;
получим сообщение об ошибке.
JavaScript весьма либерально относится к тому, как мы пишем его выражения. Благодаря этому мы можем форматировать JavaScript-код с помощью разрывов строк и пробелов для удобства его чтения.
Комментарии JavaScript
Из глав 2 и 7 мы знаем о существовании комментариев — особых фрагментов кода HTML и CSS, которые не обрабатываются Web-обозревателем и служат для того, чтобы Web-дизайнер смог оставить какие-либо заметки для себя или своих коллег. Было бы странно, если бы JavaScript не предоставлял аналогичной возможности.
Комментарии JavaScript бывают двух видов.
Комментарий, состоящий из одной строки, создают с помощью символа / (слэш), который помещают в самом начале строки комментария:
/ Это комментарий
var dNow = new Date();
Однострочный комментарий начинается с символа / и заканчивается концом строки.
Комментарий, состоящий из произвольного числа строк, создают с помощью последовательностей символов /* и */. Между ними помещают строки, которые станут комментарием:
/* Это комментарий, состоящий из нескольких строк. */ var dNow = new Date();
Многострочный комментарий начинается с последовательности символов /* и заканчивается последовательностью */.
|