Главное меню

Объекты. Экземпляры объектов


Итак, мы познакомились с типами данных, переменными, константами, операторами, простыми и сложными выражениями, функциями и массивами. Но это была, так сказать, присказка, а сказка будет впереди. Настала пора узнать о самых сложных структурах данных 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).

Экземпляры объекта Object

После выполнения инициализатора 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();

Многострочный комментарий начинается с последовательности символов /* и заканчивается последовательностью */.