<?xml version="1.0" encoding="windows-1251"?>
<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink">
<description><title-info><genre>computers</genre>
<author xmlns="http://www.w3.org/TR/xhtml1/strict">
<first-name>Марк</first-name><last-name>Кан</last-name></author>
<book-title>Основы программирования на JavaScript</book-title>
<annotation><p>Курс посвящен изучению языка программирования JavaScript.</p>
<p>JavaScript является языком сценариев (скриптов), который применяют в основном для создания на Web-страницах интерактивных элементов. Его можно использовать для построения меню, проверки правильности заполнения форм, смены изображений или для чего-то еще, что можно сделать на Web-странице.</p></annotation>
<keywords/><date/><lang>ru</lang></title-info>
<document-info>
<author><first-name>Евгений</first-name><last-name>Резниченко</last-name></author><date>18.10.2009</date><id>intuit_ru_course01-232</id>
<author><first-name>Sergey</first-name><last-name>R</last-name></author><date>12.07.2012</date><version>0.991</version>
</document-info></description>

<body><section xmlns="http://www.w3.org/TR/xhtml1/strict"><image l:href="#intuit_logo"/><p>
	Автор:
<strong>Кан Марк</strong></p><empty-line/><p>
	Название:
	<strong>Основы программирования на JavaScript</strong></p><empty-line/><section><title>Содержание</title><p><p> 
<a l:href="#1.lecture">
Лекция 1.
 Язык сценариев JavaScript</a></p><p> 
<a l:href="#2.lecture">
Лекция 2.
 Операторы и функции</a></p><p> 
<a l:href="#3.lecture">
Лекция 3.
 Формы и циклы</a></p><p> 
<a l:href="#4.lecture">
Лекция 4.
 Функции и концепция объектов</a></p><p> 
<a l:href="#5.lecture">
Лекция 5.
 Строки, числа и массивы</a></p><p> 
<a l:href="#6.lecture">
Лекция 6.
 Объектная модель документа</a></p><p> 
<a l:href="#7.lecture">
Лекция 7.
 Объект документа и объект окна</a></p><p> 
<a l:href="#8.lecture">
Лекция 8.
 Основы объектно-ориентированного программирования</a></p><p> 
<a l:href="#9.lecture">
Лекция 9.
 Наследование и замыкание</a></p><p> 
<a l:href="#10.lecture">
Лекция 10.
 Основы приложений AJAX</a></p><p> 
<a l:href="#11.lecture">
Лекция 11.
 Обработка ошибок в JavaScript</a></p><p> 
<a l:href="#12.lecture">
Лекция 12.
 Рекурсия</a></p><p><a l:href="#lectures_adds">Дополнения</a></p><p><p> 
<a l:href="#13.lecture">
Дополнение.
 Краткое руководство по AJAX</a></p><p> 
<a l:href="#14.lecture">
Дополнение.
 Учебное руководство по XHTML</a></p></p></p></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="1.lecture"><title><p>Лекция 1.
 Язык сценариев JavaScript</p></title><annotation>Введение в язык сценариев JavaScript.</annotation><section id="1.section.1"><p><emphasis>JavaScript</emphasis> является языком сценариев (скриптов), который применяют в основном для создания на Web-страницах интерактивных элементов. Его можно использовать для построения меню, проверки правильности заполнения форм, смены изображений или для чего-то еще, что можно сделать на Web-странице. Если взглянуть на Google Maps или службу GMail компании Google, то можно понять, на что способен сегодня язык <emphasis>JavaScript</emphasis>.</p><p>Так как <emphasis>JavaScript</emphasis> является в настоящее время единственным языком сценариев, который поддерживают все основные браузеры Web (<emphasis>Internet Explorer</emphasis>,  <emphasis>Firefox</emphasis>,  <emphasis>Netscape</emphasis>,  <emphasis>Safari</emphasis>,  <emphasis>Opera</emphasis>,  <emphasis>Camino</emphasis>  и т.д.), то он используется очень широко.</p><p>Код <emphasis>JavaScript</emphasis> обычно выполняется Web-браузером клиента, и в этом случае он называется сценарием на стороне клиента.  Но код  <emphasis>JavaScript</emphasis> можно выполнять также на Web-сервере для формирования документов <emphasis>HTML</emphasis>, воплощая тем самым сценарий на стороне сервера. Хотя использование <emphasis>JavaScript</emphasis> обычно ограничивается сценариями на стороне клиента, он является также очень мощным серверным языком.</p><p>При создании кода <emphasis>JavaScript</emphasis> требуется фактически только текстовый редактор и Web-браузер. Знание <emphasis>HTML</emphasis> и <emphasis>CSS</emphasis> будет играть определенно положительную роль, и если вы захотите использовать навыки <emphasis>JavaScript</emphasis> на Web-сайте, то понадобится также Web-сайт. Если у вас уже есть Web-сайт, то отлично! Если нет, то существует множество бесплатных серверов, которые можно использовать для размещения своих страниц.</p><p>Что касается текстового редактора, то в Windows имеется редактор NotePad. Хотя этого будет достаточно для редактирования <emphasis>JavaScript</emphasis>, <emphasis>HTML</emphasis> и <emphasis>CSS</emphasis>, более мощный редактор, такой, например, как EditPlus или другой, может оказаться  более удобным.</p><p>Ну, а теперь можно перейти к созданию сценария <emphasis>JavaScript</emphasis>!</p><p>Прежде всего, необходимо узнать, как добавить сценарий <emphasis>JavaScript</emphasis> на страницу <emphasis>HTML</emphasis>. Это можно сделать одним из двух способов: поместить теги <emphasis>Script</emphasis> на Web-странице и расположить код <emphasis>JavaScript</emphasis> внутри этих тегов, или  поместить весь код <emphasis>JavaScript</emphasis> в отдельный файл и связаться с ним с помощью тега <emphasis>Script</emphasis>.</p><p>Любой из этих методов вполне допустим, но они имеют разное назначение. Если имеется небольшой код, который будет использоваться только на одной странице, то размещение его между тегами <emphasis>Script</emphasis> будет хорошим решением. Если, однако, имеется большой фрагмент кода, который будет использоваться на нескольких страницах, то, наверно, лучше поместить этот код <emphasis>JavaScript</emphasis> в отдельный файл и соединиться с ним. 
Это делается для того, чтобы не нужно было загружать этот код всякий раз при посещении различных страниц. Код загружается один раз, и браузер сохраняет его для последующего использования. Это похоже на то, как используются каскадные таблицы стилей  (<emphasis>CSS</emphasis>).</p><p>Ниже приведены примеры двух способов подключения кода <emphasis>JavaScript</emphasis>:</p><empty-line/><p id=""></p><p>
&lt;script type="text/javascript"&gt;&lt;/script&gt;</p><p>
</p><p>
&lt;script type="text/javascript" src="scripts/JavaScriptFile.js"&gt;&lt;/script&gt;</p><p>
</p><empty-line/><p>В первом примере, код <emphasis>JavaScript</emphasis> помещается между символами <emphasis>&gt;</emphasis> и <emphasis>&lt;</emphasis>, прямо перед <emphasis>&lt;/script&gt;</emphasis>. Если вы совершенно не знаете, как работает Web-страница, то вот пример того, как устроена страница <emphasis>HTML</emphasis>:</p><empty-line/><p id=""></p><p>
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"&gt;</p><p>
&lt;HTML&gt;</p><p>
&lt;HEAD&gt;</p><p>
&lt;TITLE&gt; Здесь располагается заголовок страницы &lt;/TITLE&gt;</p><p>
&lt;META NAME="Generator" CONTENT="EditPlus"&gt;</p><p>
&lt;META NAME="Author" CONTENT="Имя автора"&gt;</p><p>
&lt;SCRIPT TYPE="text/javascript"&gt;</p><p>
&lt;/SCRIPT&gt;</p><p>
&lt;/HEAD&gt;</p><p>
</p><p>
&lt;BODY&gt;</p><p>
Здесь располагается основная содержательная часть Web-страницы (тело).</p><p>
&lt;/BODY&gt;</p><p>
&lt;/HTML&gt;</p><p>
</p><empty-line/><p>Сохраните этот файл где-нибудь на своем компьютере с расширением <emphasis>.html</emphasis>, так, чтобы полное имя файла было, например, таким: <emphasis>JavaScript_Lecture_1.html</emphasis>. После сохранения файла сделайте на нем двойной щелчок мышью, чтобы открыть в используемом по умолчанию браузере.</p><p>Почти любой язык программирования в мире имеет дело с объектами, называемыми "переменными", и <emphasis>JavaScript</emphasis> не является исключением. Переменная является просто элементом данных с присоединенным к нему именем. Она может содержать число, слово или предложение (называемые строками - <emphasis>String</emphasis>) или объект (<emphasis>Object</emphasis>), о которых будет рассказано позже. Если коду необходимо сообщить, что имеется <emphasis>5</emphasis> яблок, то можно создать переменную с именем <emphasis>apples</emphasis> и задать ей значение <emphasis>5</emphasis>.  Давайте сейчас это сделаем.  В <emphasis>JavaScript</emphasis> для определения переменной используется ключевое слово <emphasis>var</emphasis>. Отметим, что <emphasis>JavaScript</emphasis> различает регистр символов, поэтому <emphasis>var</emphasis> означает не то же самое, что <emphasis>VAR</emphasis> или <emphasis>Var</emphasis>.</p><empty-line/><p id=""></p><p>
var apples = 5;</p><p>
</p><empty-line/><p>Необходимо сделать два важных замечания в отношении этого небольшого фрагмента кода. Первое: требуется помнить о том, что <emphasis>JavaScript</emphasis> является "слабо типизированным" языком. Это означает, что при определении переменных не требуется указывать, какого они типа: будут ли они числами, строками, объектами, и т.д. Во многих других языках необходимо делать это различие.</p><p>Второе: обратите внимание на точку с запятой (<emphasis>;</emphasis>) в конце строки. Это говорит интерпретатору <emphasis>JavaScript</emphasis>, что вы закончили делать то, что делали в данный момент,  - в нашем случае это задание значения <emphasis>5</emphasis> переменной <emphasis>apples</emphasis>. Хотя точка с запятой не является обязательной в <emphasis>JavaScript</emphasis>, лучше привыкнуть ее использовать.</p><p>Итак, мы определили в коде, что имеется <emphasis>5</emphasis> яблок. Что дальше? Информация о яблоках имеется в коде, но никто об этом не знает. Надо сообщить о яблоках! Одним из наиболее распространенных методов вывода простого сообщения пользователю является отправка уведомления (<emphasis>alert</emphasis>):</p><empty-line/><p id=""></p><p>
var apples = 5;</p><p>
alert('Имеется ' + apples + ' яблок!');</p><p>
</p><empty-line/><p>Если протестировать этот сценарий, то на экране появится окно с сообщением " <emphasis>Имеется 5 яблок!</emphasis>"  Сейчас подходящее время, чтобы ввести строки (<emphasis>String</emphasis>) и так называемую конкатенацию или соединение строк. Строка является просто небольшим фрагментом текста и может содержать любой текст. В <emphasis>JavaScript</emphasis> мы сообщаем коду, что имеется строка, заключая ее в одиночные или двойные кавычки (<emphasis>"</emphasis> или <emphasis>'</emphasis>). Можно использовать любой тип кавычек. Знаки плюс (<emphasis>+</emphasis>) в примере выше сообщают коду, что мы соединяем строку  с предыдущей строкой.</p><p>Итак мы имеем строку "<emphasis>Имеется</emphasis>" за которой следует переменная <emphasis>apples</emphasis> (равная <emphasis>5</emphasis>), за которой следует еще одна строка "<emphasis>яблок!</emphasis>". Соединим их вместе и получим "<emphasis>Имеется 5 яблок!</emphasis>". Команда <emphasis>alert</emphasis> получает то, что  ей передается (то, что находится между скобок) и открывает окно с текстом.</p><p>Что если мы хотим предложить пользователю съесть яблоко? Можно, например,  спросить, сколько яблок он хотел бы съесть:</p><empty-line/><p id=""></p><p>
var apples = 5;</p><p>
alert('Имеется ' + apples + ' яблок!');</p><p>
</p><p>
var eat    = prompt('Сколько яблок вы хотите съесть?', '1');</p><p>
</p><empty-line/><p><emphasis>prompt</emphasis> является другой встроенной функцией, аналогичной <emphasis>alert</emphasis>. Однако вместо простого вывода информации она также получает ввод от пользователя.  В данном случае мы спрашиваем у пользователя, сколько яблок он хотел бы съесть.  <emphasis>'1'</emphasis>  в коде сообщает функции <emphasis>prompt</emphasis>, что значением по умолчанию для количества яблок будет <emphasis>1</emphasis>, так как люди обычно едят только одно яблоко за раз. Однако пользователь может изменить это значение на любое другое. Когда пользователь щелкнет на кнопке <emphasis>OK</emphasis>, переменной <emphasis>eat</emphasis> будет задано значение этого ввода. Поэтому если пользователь введет <emphasis>2</emphasis>, то <emphasis>eat</emphasis>  будет равно <emphasis>2</emphasis>.</p><p>Поэтому, если пользователь съел <emphasis>2</emphasis> яблока, то останется <emphasis>3</emphasis>, так? Поэтому выполним несколько простых математических операций и покажем результат.</p><empty-line/><p id=""></p><p>
var apples = 5;</p><p>
alert('Имеется ' + apples + ' яблок!');</p><p>
</p><p>
var eat    = prompt('Сколько яблок вы хотите съесть?', '1');</p><p>
</p><p>
apples    -= parseInt(eat);</p><p>
alert('А теперь имеется только' + apples + ' яблок!');</p><p>
</p><empty-line/><p>Здесь мы видим два новых элемента. Прежде всего, обращение к функции <emphasis>parseInt</emphasis>, которая получает строку и возвращает число. Так как для выполнения математических операций требуются числа, то это гарантирует, что мы имеем число. Если пользователь введет в поле <emphasis>2</emphasis>,  то <emphasis>parseInt</emphasis> превратит это в число <emphasis>2</emphasis>.</p><p>Затем, оператор <emphasis>-=</emphasis>, который означает вычитание из левой части оператора значения правой части.  Поэтому значение переменной <emphasis>eat</emphasis> вычитается из переменной <emphasis>apples</emphasis>.  Можно также записать эту строку следующим образом:</p><empty-line/><p id=""></p><p>
apples = apples - parseInt(eat);</p><p>
</p><empty-line/><p>Это означает в точности то же самое и может быть немного легче для понимания. 
Теперь, когда известно, сколько осталось яблок, мы еще раз сообщаем пользователю эту информацию.</p><p>Существуют другие операторы, подобные <emphasis>-=</emphasis>, которые делают похожие вещи. Всего имеется 8 обычных арифметических операторов:</p><empty-line/><p id=""></p><p>
+</p><p>
-</p><p>
/</p><p>
*</p><p>
+=</p><p>
-=</p><p>
/=</p><p>
*=</p><p>
</p><empty-line/><p>Вот и все для начала. В <a l:href="">следующей лекции</a>  мы добавим в код проверку, введем операторы <emphasis>if</emphasis> и <emphasis>else</emphasis> и вкратце познакомимся с функциями.</p></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="2.lecture"><title><p>Лекция 2.
 Операторы и функции</p></title><annotation>Основы проверки сценариев. Операторы if и else. Способы записи комментариев. Краткое знакомство с функциями.</annotation><section id="2.section.1"><p>При тестировании сценария, написанного в <a l:href="">предыдущей лекции</a>, можно заметить, что  результат, получаемый из <emphasis>prompt</emphasis>, требует некоторой проверки. Когда сценарий спрашивает, сколько яблок желает съесть пользователь, то пользователь может ввести число больше <emphasis>5</emphasis>, меньше <emphasis>0</emphasis> или что-то, что вообще не является числом. В каждом из таких случаев желательно информировать пользователей, что введено недопустимое значение.</p><p>Так как в этом сценарии имеется только <emphasis>5</emphasis> яблок, то это максимальное количество яблок, которое может  получить пользователь. Поэтому начнем с проверки, что введенное число не больше <emphasis>5</emphasis>.</p><empty-line/><p id=""></p><p>
var apples = 5;</p><p>
alert('Имеется ' + apples + ' яблок!');</p><p>
</p><p>
var eat    = prompt('Сколько яблок вы хотите съесть?', '1');</p><p>
</p><p>
var eaten  = parseInt(eat);</p><p>
if(eaten &gt; 5){</p><p>
  alert('Простите, но имеется только 5 яблок.' + 'Вы не можете съесть ' + eaten + ' яблок!');</p><p>
} else {</p><p>
  apples    -= eaten;</p><p>
  alert('А теперь имеется только ' + apples + ' яблок!');</p><p>
}</p><p>
</p><empty-line/><p>Основными новыми понятиями здесь являются операторы  <emphasis>if</emphasis> и <emphasis>else</emphasis>.  Операторы <emphasis>if</emphasis> и <emphasis>else</emphasis> достаточно легко понять. Приведенный выше код дает возможность сказать: "Если пользователь выбрал для еды более <emphasis>5</emphasis> яблок, то сообщите ему, что такого количества яблок нет. Иначе позвольте ему съесть столько яблок, сколько он попросит.".</p><p>Основной синтаксис оператора <emphasis>if / else</emphasis> следующий:</p><empty-line/><p id=""></p><p>
if(условие){</p><p>
  // код, который выполняется, когда справедливо условие if </p><p>
} else {</p><p>
  // код, который выполняется, когда условие if ложно </p><p>
}</p><p>
</p><empty-line/><p>Необходимо отметить открывающую и закрывающую скобки, <emphasis>{</emphasis>  и  <emphasis>}</emphasis>, в приведенном выше коде. Открывающая скобка сообщает коду, где начинается блок кода, а закрывающая скобка указывает коду, где блок заканчивается. Поэтому все между <emphasis>{</emphasis>  и <emphasis>}</emphasis> выполняется как часть оператора <emphasis>if</emphasis>. Необходимо отметить, что закрывающая скобка оператора <emphasis>if</emphasis> размещается непосредственно перед ключевым словом <emphasis>else</emphasis>. Оператор <emphasis>else</emphasis> имеет свой собственный набор скобок и свой собственный блок для выполнения.</p><p>Две косые черты  <emphasis>//</emphasis> в приведенном примере говорят коду, что здесь находится комментарий. Комментарий является частью кода, который не выполняется. Они обычно используются для описания функций реального кода, чтобы не требовалось изучать код для выяснения, что он делает.  Если, например, имеется очень длинный фрагмент кода, который проверяет входящие данные формы, то будет вполне разумно вставить комментарий, говорящий что-нибудь вроде "<emphasis>Следующий код проверяет ввод пользователя в форму</emphasis>". В этом случае любой, кто будет просматривать код, или сам автор кода несколько месяцев спустя после написания, сразу поймет, что этот код делает.</p><p>В <emphasis>JavaScript</emphasis> существует два способа записи комментариев. Первый, который мы уже видели, состоит в использовании <emphasis>//</emphasis>. Все следующее за   <emphasis>//</emphasis> до конца строки считается комментарием и поэтому игнорируется при выполнении кода. Другой способ состоит в использовании комбинаций символов <emphasis>/*</emphasis> и <emphasis>*/</emphasis>, в этом случае все, что находится между ними, игнорируется.</p><empty-line/><p id=""></p><p>
// это однострочный комментарий</p><p>
</p><p>
/*</p><p>
если требуется более длинный комментарий, то  </p><p>
лучше использовать "блочный комментарий".</p><p>
 </p><p>
Этот комментарий является блочным комментарием, </p><p>
и полностью игнорируется при выполнении кода </p><p>
*/</p><p>
</p><empty-line/><p>Для короткого сценария комментарии не всегда нужны. Но когда код  длинный, они становятся необходимостью. Программистам очень часто приходится просматривать тысячи строк кода в попытке найти место для исправления ошибки. Если код имеет хорошие комментарии, то достаточно легко почти точно определить, где находится нужный код.</p><p>Вернемся к нашему оператору <emphasis>if</emphasis>,</p><empty-line/><p id=""></p><p>
if(eaten &gt; 5){</p><p>
  alert('Простите, но имеется только 5 яблок.  </p><p>
 Вы не можете съесть ' + eaten + ' яблок!');</p><p>
} else {</p><p>
  apples    -= eaten;</p><p>
  alert('А теперь имеется только ' + apples + ' яблок!');</p><p>
}</p><p>
</p><empty-line/><p>Можно видеть, что условием является <emphasis>eaten &gt; 5</emphasis>.  Знак <emphasis>&gt;</emphasis>  означает "<emphasis>больше чем</emphasis>", так что это условие означает "<emphasis>если eaten больше 5</emphasis>". Аналогично, <emphasis>&lt;</emphasis> означает "<emphasis>меньше чем</emphasis>".</p><p>Существует два других аналогичных знака <emphasis>&gt;=</emphasis> и <emphasis>&lt;=</emphasis>, которые  означают "<emphasis>больше чем или равно</emphasis>" и "<emphasis>меньше чем или равно</emphasis>" соответственно.</p><p>В приведенном  выше коде мы сообщаем пользователю о том, что он ввел значение больше <emphasis>5</emphasis> яблок. Только если он выбрал меньше <emphasis>5</emphasis> яблок, это число вычитается из текущего количества яблок и затем пользователю сообщается, сколько яблок осталось.  
Однако существует еще два возможных случая. Что, если пользователь введет число меньше <emphasis>0</emphasis>? Что, если он введет значение, которое не является числом?  Первый случай читатель может теперь обработать самостоятельно. Второй случай требует использования другой встроенной функции, <emphasis>isNaN</emphasis>.  При попытке преобразовать что-нибудь в число с помощью функции <emphasis>parseInt</emphasis>, возвращается значение <emphasis>NaN</emphasis>, если функция не может выполнить операцию. <emphasis>NaN</emphasis> означает <emphasis>Not a Number</emphasis> (Не число). Если вызвать функцию <emphasis>parseInt</emphasis>, например, со значением <emphasis>apple</emphasis>, то будет получено значение <emphasis>NaN</emphasis>, так как слово <emphasis>apple</emphasis> не является числом.</p><empty-line/><p id=""></p><p>
var apples = 5;</p><p>
alert('Имеется ' + apples + ' яблок!');</p><p>
</p><p>
var eat    = prompt('Сколько яблок вы хотите съесть?', '1');</p><p>
</p><p>
var eaten  = parseInt(eat);</p><p>
if(isNaN(eaten)){</p><p>
  alert('Вы должны ввести допустимое число яблок!');</p><p>
} else if(eaten &gt; apples){</p><p>
  alert('Простите, но имеется только ' + apples + ' яблок.  </p><p>
 Вы не можете съесть ' + eaten + </p><p>
     ' яблок!');</p><p>
} else if(eaten &lt; 0){</p><p>
  alert('Простите, но вы не можете съесть </p><p>
  отрицательное количество яблок!');</p><p>
} else {</p><p>
  apples -= eaten;</p><p>
  alert('А теперь имеется только ' + apples + ' яблок!');</p><p>
}</p><p>
</p><empty-line/><p>Теперь все это должно быть понятно читателю. Прежде всего проверяется, что введено допустимое значение. Если значение недопустимо, выводится соответствующее сообщение. Затем проверяется, что введенное число не превышает количество  существующих яблок, а затем - что это число не является отрицательным. Если все эти проверки проходят успешно, пользователь сможет съесть столько яблок, сколько захочет.  В коде сделано еще одно изменение, вместо <emphasis>if(eaten &gt; 5)</emphasis> используется <emphasis>if(eaten &gt; apples)</emphasis>. Если в последующем количество имеющихся яблок  <emphasis>var apples = 5;</emphasis> изменится, то это изменение пришлось бы делать только в одном месте. Старайтесь всегда использовать в коде переменные. Если значения "жестко закодированы", как было сделано ранее в коде <emphasis>if(eaten &gt; 5)</emphasis>, то очень часто при внесении изменений придется подолгу искать эти жестко закодированные значения, чтобы убедиться, что внесены все необходимые изменения.</p><p>Если пользователь ввел каким-либо образом недопустимое значение, то можно попросить его повторно ввести количество яблок, которое он хочет съесть. Одним из способов сделать это было бы копирование всего кода несколько раз. Однако обычно это не самое лучшее решение. Что, если пользователь вводит недопустимое значение снова и снова? Можно продолжить копирование кода, но легко видеть, что это крайне неэффективно и очень трудно поддерживать код в рабочем состоянии.</p><p>В этом случае лучшим решением будет использование так называемой функции. Функция содержит код, который выполняет определенную задачу. Мы уже видели использование функций <emphasis>alert</emphasis>, <emphasis>prompt</emphasis>, <emphasis>parseInt</emphasis> и <emphasis>isNaN</emphasis>, которые встроены в язык <emphasis>JavaScript</emphasis>.  Преимущество использования функций состоит в том, что можно выполнять один и тот же блок кода снова и снова, не копируя этот код,  Для выполнения функции необходимо написать ее имя, за которым следуют скобки <emphasis> ()</emphasis>, а все значения, передаваемые в функцию, записываются между скобками.</p><empty-line/><p id=""></p><p>
var apples = 5;</p><p>
</p><p>
function eatApples(){</p><p>
  alert('Имеется ' + apples + ' яблок!');</p><p>
</p><p>
  var eat  = prompt('Сколько яблок  вы хотите съесть?', '1');</p><p>
</p><p>
  var eaten  = parseInt(eat);</p><p>
  if(isNaN(eaten)){</p><p>
    alert('Вы должны ввести допустимое число яблок!');</p><p>
    eatApples();</p><p>
  } else if(eaten &gt; apples){</p><p>
    alert('Простите, но имеется только ' + apples + ' яблок.  </p><p>
 Вы не можете съесть ' + eaten + </p><p>
       ' яблок!');</p><p>
    eatApples();</p><p>
  } else if(eaten &lt; 0){</p><p>
    alert('Простите, но вы не можете съесть </p><p>
 отрицательное количество яблок!');</p><p>
    eatApples();</p><p>
  } else {</p><p>
    apples -= eaten;</p><p>
    alert('А теперь имеется только ' + apples + ' яблок!');</p><p>
    if(apples &gt; 0){</p><p>
      if(confirm('Не хотите съесть еще яблочко?')){</p><p>
        eatApples();</p><p>
      }</p><p>
    } else {</p><p>
      alert('Яблок больше нет!');</p><p>
    }</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p>Здесь весь наш код записан в виде функции с именем <emphasis>eatApples</emphasis>. Можно видеть, что каждый раз, когда пользователь вводит неверное значение,  снова вызывается функция <emphasis>eatApples();</emphasis>, чтобы пользователь мог ввести новое значение.  Когда пользователь вводит допустимое значение, то он либо может еще есть яблоки, либо, если все яблоки закончились, он получит соответствующее сообщение. Здесь используется также одна новая функция, <emphasis>confirm</emphasis>.  Функция <emphasis>confirm</emphasis> просто выводит пользователю приглашение <emphasis>OK or Cancel</emphasis> ("Да или Отмена"). Если пользователь нажмет кнопку "<emphasis>OK</emphasis>", то функция возвращает значение <emphasis>true</emphasis> (да). Если пользователь нажмет кнопку <emphasis>Cancel</emphasis> или просто закроет окно, то функция  <emphasis>confirm</emphasis> возвращает значение <emphasis>false</emphasis> (нет). Поэтому в нашем примере функция <emphasis>eatApples</emphasis> вызывается снова только в том случае, когда пользователь щелкнет на кнопке <emphasis>OK</emphasis>.</p><p>В конце этой лекции будет рассмотрена область действия переменной. Как можно видеть, в последнем примере переменная <emphasis>apples</emphasis> находится вне функции <emphasis>eatApples</emphasis>. Это делает переменную <emphasis>apples</emphasis> "глобальной переменной", т.е. она будет доступна из любой функции.  Переменная <emphasis>eat</emphasis>, с другой стороны, является локальной переменной и существует только внутри функции  <emphasis>eatApples</emphasis>. Кроме того, каждый раз при вызове функции <emphasis>eatApples</emphasis> переменная <emphasis>eat</emphasis> не будет существовать, пока не будет снова определена функцией <emphasis>prompt</emphasis>.</p><p>Чтобы увидеть эту концепцию в действии, напишем две простые функции счета:</p><empty-line/><p id=""></p><p>
function counting1(){</p><p>
  var count = 0;</p><p>
  count++;</p><p>
</p><p>
  alert(count);</p><p>
}</p><p>
</p><p>
</p><p>
var count = 0;</p><p>
function counting2(){</p><p>
  count++;</p><p>
</p><p>
  alert(count);</p><p>
}</p><p>
</p><empty-line/><p>Если запустить этот пример в браузере и щелкнуть на каждой кнопке несколько раз, то можно заметить, что <emphasis>counting1</emphasis> всегда выдает одно и то же значение, <emphasis>1</emphasis>. <emphasis>counting2</emphasis>, с другой стороны, выдает увеличивающееся число. Почему это происходит?  Посмотрим просто сначала на <emphasis>counting1</emphasis>. Можно видеть, что каждый раз при выполнении <emphasis>counting1</emphasis>  прежде всего создается переменная <emphasis>count</emphasis>  и ее значение задается равным <emphasis>0</emphasis>. В следующей строке переменная <emphasis>count</emphasis>  увеличивается на <emphasis>1</emphasis>.</p><p>Оператор <emphasis>++</emphasis>  пока еще не встречался. <emphasis>count++</emphasis>  просто увеличивает <emphasis>count</emphasis>  на <emphasis>1</emphasis>. Другими словами, это в точности то же самое, что написать <emphasis>count += 1</emphasis> или <emphasis>count = count + 1</emphasis>.  Поскольку увеличение на <emphasis>1</emphasis> является в программировании очень распространенным действием, то для него существует специальный оператор. Аналогично оператор   <emphasis>--</emphasis> вычитает <emphasis>1</emphasis> из переменной: <emphasis>count--</emphasis>.</p><p>Каждый раз, когда функция <emphasis>counting1</emphasis> выполняет <emphasis>alert(count)</emphasis>, она сообщает значение новой переменной <emphasis>count</emphasis> , которое только что было  определено как <emphasis>0+1</emphasis>.</p><p>Теперь посмотрим на <emphasis>counting2</emphasis>. Можно видеть, что переменная <emphasis>count</emphasis>  в этом случае находится вне функции.  Даже до вызова этой функции значение <emphasis>count</emphasis>  задано как <emphasis>0</emphasis>. При вызове <emphasis>counting2</emphasis> прежде всего происходит увеличение переменной <emphasis>count</emphasis>  на <emphasis>1</emphasis>. Так как мы не восстанавливаем значение <emphasis>count</emphasis>  в <emphasis>0</emphasis>, как в случае <emphasis>counting1</emphasis>, то переменная <emphasis>count</emphasis>  продолжает сохранять свое значение, и все происходит, как и предполагалось.</p><p>Теперь читатель получил общее понимание некоторых фундаментальных понятий программирования и <emphasis>JavaScript</emphasis>, в частности. В <a l:href="">следующей лекции</a>  будут рассмотрены циклы и формы.</p></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="3.lecture"><title><p>Лекция 3.
 Формы и циклы</p></title><annotation> Основы работы с полями форм и с функциями циклов.</annotation><section id="3.section.1"><p>В <a l:href="">предыдущей лекции</a>  были рассмотрены операторы <emphasis>if</emphasis>/<emphasis>else</emphasis>, основы проверки и функций. Если в ходе дальнейшего чтения возникнут какие-то вопросы, то имеет смысл еще раз прочитать <a l:href=""> предыдущую лекцию</a>.</p><p>Мы знаем теперь, как проверять данные, но при создании кода <emphasis>JavaScript</emphasis> обычно требуется проверять не оставшееся количество воображаемых яблок. Одной из наиболее общих областей применения <emphasis>JavaScript</emphasis> являются поля формы. Предположим, например, что имеется простая контактная форма. Иногда требуется убедиться, что пользователь ввел в форму свое имя или что он выбрал как минимум одну радио-кнопку для вопроса. Вот пример такой формы:</p><empty-line/><p id=""></p><p>
Имя:      Ваш любимый цвет:  Синий    Желтый</p><p>
                             Красный  Черный</p><p>
                             Зеленый  Другой</p><p>
Фамилия:</p><p>
Адрес Email:  </p><p>
</p><p>
Отправить форму   Очистить форму         Зафиксировать форму на месте</p><p>
</p><empty-line/><p>Ниже представлен код этой формы. Он приведен только для иллюстрации.</p><empty-line/><p id=""></p><p>
&lt;form name="tutform" onsubmit="return noform();" class="codesnip" </p><p>
  style="background-color:#FFF;z-index:10;"&gt;</p><p>
&lt;table width="100%"&gt;</p><p>
  &lt;tr&gt;</p><p>
    &lt;td&gt;Имя:&lt;/td&gt;</p><p>
    &lt;td&gt;&lt;input name="firstname"&gt;&lt;/td&gt;</p><p>
    &lt;td&gt;Ваш любимый цвет:&lt;/td&gt;</p><p>
    &lt;td rowspan="3" valign="top"&gt;</p><p>
      &lt;input type="radio" name="color" value="blue"&gt;Синий&lt;br /&gt;</p><p>
      &lt;input type="radio" name="color" value="red"&gt;Красный&lt;br /&gt;</p><p>
      &lt;input type="radio" name="color" value="green"&gt;Зеленый</p><p>
    &lt;/td&gt;</p><p>
    &lt;td rowspan="3" valign="top"&gt;</p><p>
      &lt;input type="radio" name="color" value="yellow"&gt;Желтый&lt;br /&gt;</p><p>
      &lt;input type="radio" name="color" value="black"&gt;Черный&lt;br /&gt;</p><p>
      &lt;input type="radio" name="color" value="other"&gt;Другой</p><p>
    &lt;/td&gt;</p><p>
  &lt;/tr&gt;</p><p>
  &lt;tr&gt;</p><p>
    &lt;td&gt;Фамилия:&lt;/td&gt;</p><p>
    &lt;td&gt;&lt;input name="lastname"&gt;&lt;/td&gt;</p><p>
  &lt;/tr&gt;</p><p>
  &lt;tr&gt;</p><p>
    &lt;td&gt;Адрес Email:&lt;/td&gt;</p><p>
    &lt;td&gt;&lt;input name="email"&gt;&lt;/td&gt;</p><p>
  &lt;/tr&gt;</p><p>
  &lt;tr&gt;</p><p>
    &lt;td colspan="2"&gt;&lt;input type="submit" value="Отправить форму"&gt;</p><p>
    &lt;input type="reset" value="Очистить форму"&gt;&lt;/td&gt;</p><p>
    &lt;td colspan="3" align="right"&gt;&lt;button id="lockbutton" </p><p>
onclick="swapLock();return false;"&gt;Зафиксировать форму на месте&lt;/button&gt;&lt;/td&gt;</p><p>
  &lt;/tr&gt;</p><p>
&lt;/table&gt;</p><p>
&lt;/form&gt;</p><p>
</p><empty-line/><p>Прежде всего необходимо узнать, как создать объект <emphasis>JavaScript</emphasis>, который ссылается на форму. Любую форму на странице можно указать с помощью конструкции <emphasis>document.forms</emphasis>.  Если имеется форма с именем <emphasis>tutform</emphasis>, то к ней можно обратиться следующим образом: <emphasis>document.forms.tutform</emphasis>.</p><p>На любые элементы внутри формы (поля ввода, поля выбора, флажки и т.д) можно ссылаться с помощью конструкции <emphasis>elements</emphasis>: <emphasis>document.forms.ИмяФормы.elements</emphasis>. Если на форме имеется поле ввода с именем <emphasis>firstname</emphasis>,  то  значение этого поля можно вывести следующим образом:</p><empty-line/><p id=""></p><p>
alert('Имя: ' + document.forms.tutform.elements.firstname.value);</p><p>
</p><empty-line/><p>Если щелкнуть на этой кнопке, а затем отправить учебную форму, то появится уведомление с тем значением, которое было введено в поле <emphasis>Имя</emphasis>. Как это происходит? Когда форма посылается на сервер, Web-браузер ищет код <emphasis>onsubmit</emphasis>. Если этот код существует, то форма выполняет его перед отправкой:</p><empty-line/><p id=""></p><p>
&lt;SCRIPT TYPE="text/javascript"&gt;</p><p>
function validateForm(){</p><p>
// код проверки формы находится здесь </p><p>
}</p><p>
&lt;/SCRIPT&gt;</p><p>
</p><p>
&lt;FORM ONSUBMIT="return validateForm();"&gt;</p><p>
&lt;!-- элементы формы находятся здесь --&gt;</p><p>
&lt;/FORM&gt;</p><p>
</p><empty-line/><p>Теперь, зная, как получить доступ к форме и элементам на этой форме, выполним некоторые основные проверки. Распространенной задачей является проверка, что именно пользователь ввел в поле ввода. Например, надо проверить, что пользователь ввел свое имя.</p><p>Как видно из предыдущего фрагмента кода, свойство "<emphasis>.value</emphasis> " объекта формы можно использовать  для получения его значения. Это работает для объектов формы любого типа. Попробуем теперь проверить, что пользователь ввел на форме свои имя и фамилию:</p><empty-line/><p id=""></p><p>
function validateForm(){</p><p>
  var form_object = document.forms.tutform;</p><p>
    if(form_object.elements.firstname.value == ''){</p><p>
    alert('Вы должны ввести свое имя!');</p><p>
    return false;</p><p>
  } else if(form_object.elements.lastname.value == ''){</p><p>
    alert('Вы должны ввести свою фамилию!');</p><p>
    return false;</p><p>
  }</p><p>
  return true;</p><p>
}</p><p>
</p><empty-line/><p>Важными моментами, которые необходимо отметить в этой функции, являются строки <emphasis>return false</emphasis>; и <emphasis>return true</emphasis>;. Если функция проверки возвращает значение <emphasis>true</emphasis>, то форма будет отправлена как обычно.  Если, однако, функция вернет значение <emphasis>false</emphasis>, то форма отправлена не будет. Необходимо сообщить пользователю, почему форма не была отправлена, поэтому в функцию вставлены уведомления (<emphasis>alert</emphasis>).</p><p>Другим важным полем для проверки в демонстрационной форме будет набор радио-кнопок "<emphasis>Любимый цвет</emphasis> ". Если щелкнуть несколько раз на этих кнопках, то можно видеть, что в данный момент времени может быть выбрана только одна из них. Но желательно знать, что пользователь выбрал хотя бы одну из этих кнопок.</p><p>Радио-кнопки и флажки на форме представляют специальную ситуацию. Часто имеется несколько радио-кнопок с одним и тем же именем, что почти всегда исключено для полей ввода, полей выбора и т.д.:</p><empty-line/><p id=""></p><p>
&lt;input type="radio" name="color" value="blue"&gt;Синий</p><p>
&lt;input type="radio" name="color" value="red"&gt;Красный </p><p>
&lt;input type="radio" name="color" value="green"&gt;Зеленый </p><p>
</p><empty-line/><p>В связи с этим существует способ доступа ко всем радио-кнопкам с одним именем. Значение <emphasis>document.forms.имяФормы.elements.имяРадиокнопок</emphasis> будет содержать список со всеми радио-кнопками. Так как необходимо проверить, что хотя бы одна радио-кнопка отмечена, то потребуется просмотреть все эти радио-кнопки. Если хотя бы одна из них отмечена, функция проверки должна вернуть <emphasis>true</emphasis>. Поэтому функция выглядит теперь следующим образом:</p><empty-line/><p id=""></p><p>
function validateForm(){</p><p>
  var radios = document.forms.tutform.elements.color;</p><p>
  for(var i=0; i&lt;radios.length; i++){</p><p>
    if(radios[i].checked) return true;</p><p>
  }</p><p>
  alert('Вы должны выбрать цвет!');</p><p>
  return false;</p><p>
}</p><p>
</p><empty-line/><p>Новым элементом в этом коде является так называемый цикл <emphasis>for</emphasis>. Он выглядит немного более сложно, чем есть в действительности, поэтому разберем его составные элементы:</p><empty-line/><p id=""></p><p>
for(var i=0; i&lt;radios.length; i++){</p><p>
</p><empty-line/><p>Внутри скобок имеется три значения, разделенные точкой с запятой. Этими значениями, по отдельности, являются:</p><empty-line/><p id=""></p><p>
var i=0</p><p>
</p><p>
i&lt;radios.length</p><p>
</p><p>
i++</p><p>
</p><empty-line/><p>Первое значение является просто заданием значения переменной. Это должно быть теперь 
понятно без проблем. Второе значение является условием проверки. Цикл <emphasis>for</emphasis> будет выполняться, пока это условие проверки возвращет <emphasis>true</emphasis>.  Как только оно вернет <emphasis>false</emphasis>, цикл <emphasis>for</emphasis> остановится и выполнение кода продолжится со следующей строки. Поэтому условие <emphasis>i&lt;radios.length</emphasis> говорит, что цикл <emphasis>for</emphasis> должен выполняться, пока переменная <emphasis>i</emphasis> меньше числа имеющихся радио-кнопок.</p><p>"<emphasis>length</emphasis>" в данном случае является свойством массива. Мы пока еще не встречались с массивами, но, упрощая, можно сказать, что <emphasis>radios.length</emphasis> возвращает просто число элементов в <emphasis>radios</emphasis>, которое в данном случае равно <emphasis>6</emphasis>, так как имеется только <emphasis>6</emphasis> радио-кнопок.  Последнее выражение цикла <emphasis>for</emphasis>, <emphasis>i++</emphasis> , является кодом, который должен выполняться после каждого шага цикла.</p><p>Говоря более простым языком, цикл <emphasis>for</emphasis> делает следующее:</p><p><strong>1</strong> задает <emphasis>i</emphasis> равным <emphasis>0</emphasis>;</p><p><strong>2</strong> проверяет, что <emphasis>i</emphasis> меньше <emphasis>radios.length</emphasis>, которое равно <emphasis>6</emphasis>;</p><p><strong>3</strong> если это справедливо (<emphasis>true</emphasis>), выполняет код в цикле <emphasis>for</emphasis>;</p><p><strong>4</strong> после выполнения кода в цикле <emphasis>for</emphasis> добавляет <emphasis>1</emphasis> к переменной <emphasis>i</emphasis>;</p><p><strong>5</strong> переходит к шагу 2, пока выполняется условие <emphasis>i&lt;radios.length</emphasis> . Это условие не выполнится после шестого выполнения цикла, когда <emphasis>i=6</emphasis>.</p><p>Существует другой тип цикла, который сейчас будет  рассмотрен, -  так называемый цикл <emphasis>while</emphasis>. Следующий код делает то же самое, что и предыдущий цикл:</p><empty-line/><p id=""></p><p>
var i=0;</p><p>
while(i&lt;radios.length){</p><p>
  if(radios[i].checked) return true;</p><p>
  i++;</p><p>
}</p><p>
alert('Вы должны выбрать цвет!');</p><p>
return false;</p><p>
</p><empty-line/><p>Можно видеть, что здесь в цикле <emphasis>while</emphasis> присутствуют точно те же  <emphasis>3</emphasis> фрагмента кода, которые имелись в цикле <emphasis>for</emphasis>:  "<emphasis>var i=0</emphasis> ", "<emphasis>i&lt;radios.length</emphasis> " и "<emphasis>i++</emphasis> ". Единственное отличие состоит в их размещении. В цикле <emphasis>while</emphasis> только проверка</p><empty-line/><p id=""></p><p>
i&lt;radios.length</p><empty-line/><p>чем-то отличается от того, что было написано раньше. Эта проверка происходит в скобках сразу после <emphasis>while</emphasis>. Переменные инициализируются перед циклом <emphasis>while</emphasis>, а увеличение <emphasis>i</emphasis>, <emphasis>i++</emphasis>,  происходит внутри цикла.</p><p>В этих циклах осталось объяснить еще одну вещь: <emphasis>if(radios[i].checked)</emphasis>. Переменная <emphasis>radios</emphasis> содержит массив радио-кнопок с именем <emphasis>color</emphasis>. Массивы будут рассмотрены в <a l:href=""> следующей лекции</a>, а здесь дадим упрощенное объяснение: <emphasis>radios[0]</emphasis> возвращает первую радио-кнопку, <emphasis>radios[1]</emphasis> возвращает вторую, <emphasis>radios[2]</emphasis> - третью, и т.д. до <emphasis>radios[5]</emphasis>, который возвращает шестую кнопку. Если кнопок будет больше, например, <emphasis>100</emphasis>, то <emphasis>radios[99]</emphasis> будет обращаться к <emphasis>100</emphasis>-ой радио-кнопке.</p><p>Все эти числа могут показаться странными. Почему <emphasis>radios[5]</emphasis> обращается к шестой радио-кнопке? В <emphasis>JavaScript</emphasis>, как и во многих других языках программирования, многие вещи начинаются с числа <emphasis>0</emphasis>, а не с <emphasis>1</emphasis>. Это просто один из таких случаев, но это встретится еще не раз.  Поэтому <emphasis>0</emphasis> является в действительности первым элементом, <emphasis>1</emphasis> - вторым, и т.д.</p><p>В форме осталось проверить еще ввод адреса e-mail.  Это в действительности достаточно сложное для проверки поле, и правильная ее реализация выходит за рамки того, что изучается в этой лекции, но можно выполнить некоторую базовую проверку. Что нужно сделать?  Мы знаем, что любой адрес e-mail должен содержать один и только один символ  <emphasis>@</emphasis>. Он должен также содержать по крайней мере одну точку после символа  <emphasis>@</emphasis> (точка отделяет имя домена от домена верхнего уровня, например, "<emphasis>intuit.ru</emphasis> ").</p><empty-line/><p id=""></p><p>
function validateForm(){</p><p>
  var email = document.forms.tutform.elements.email.value;</p><p>
  if(email.indexOf('@')&lt;0){</p><p>
    alert('В адресе e-mail должен присутствовать символ @');</p><p>
    return false;</p><p>
  } else if(email.indexOf('@') != email.lastIndexOf('@')){</p><p>
    alert('В адресе e-mail не может быть больше одного символа @');</p><p>
    return false;</p><p>
  } else if(email.indexOf('.')&lt;0){</p><p>
    alert('В адресе e-mail должна присутствовать хотя бы одна точка.');</p><p>
    return false;</p><p>
  } else if(email.lastIndexOf('.')&lt;email.indexOf('@')){</p><p>
    alert('В адресе e-mail должна присутствовать хотя бы одна точка после символа @');</p><p>
    return false;</p><p>
  }</p><p>
  return true;</p><p>
}</p><p>
</p><empty-line/><p>Здесь имеются две новые сходные функции, которые требуют пояснения. Функция <emphasis>indexOf</emphasis> возвращает число, определяющее позицию одной строки в другой строке. <emphasis>'abcdef'.indexOf('a')</emphasis> вернет <emphasis>0</emphasis> (здесь <emphasis>0</emphasis> снова означает первую позицию).  <emphasis>'abcdef'.indexOf('cdef')</emphasis> вернет <emphasis>2</emphasis>, а <emphasis>'abcdef'.indexOf('aaa')</emphasis> вернет <emphasis>-1</emphasis>. <emphasis>-1</emphasis> означает, что строка не найдена. Во многих случаях возвращается <emphasis>-1</emphasis>, когда функция не может получить результат.</p><p>Аналогично,  функция <emphasis>lastIndexOf</emphasis> возвращает позицию последнего вхождения одной строки в другую.  <emphasis>'abcba'.lastIndexOf('a')</emphasis> вернет <emphasis>4</emphasis>, в то время как <emphasis>'abcba'.indexOf('a')</emphasis> вернет <emphasis>0</emphasis>.</p><p>Поэтому в нашем коде  первый оператор <emphasis>if</emphasis> проверяет, что в адресе e-mail имеется хотя бы один символ <emphasis>'@'</emphasis>. Если такого символа нет, то  <emphasis>email.indexOf('@')</emphasis>  вернет <emphasis>-1</emphasis> и оператор <emphasis>if</emphasis>  вернет <emphasis>false</emphasis>.</p><p>Следующий оператор соединяет <emphasis>indexOf</emphasis> и <emphasis>lastIndexOf</emphasis>. Если в адресе e-mail имеется более одного символа <emphasis>@</emphasis>, то две эти функции вернут различные значения, как в приведенном выше примере с <emphasis>'abcba'</emphasis>.  Если имеется только один символ <emphasis>@</emphasis>, то эти функции вернут одно и то же значение. Поэтому мы проверяем эти значения на неравенство.</p><p>Третий оператор по сути идентичен первому, только он проверяет <emphasis>'.'</emphasis>, а не <emphasis>'@'</emphasis>.</p><p>Наконец, четвертый оператор <emphasis>if</emphasis> проверяет, что в адресе e-mail имеется как минимум одна точка после символа <emphasis>@</emphasis>.</p><p>Недостаток этого метода состоит в том, что простая строка "<emphasis>@.</emphasis>" пройдет проверку. Должно быть очевидно, что она не является допустимым адресом e-mail. Существует другой метод для проверки адреса e-mail и для проверки множества других вещей. Это делается с помощью так называемых "регулярных выражений". Хотя регулярные выражения здесь рассматриваться не будут, ниже приведен пример проверки адреса e-mail, который остается читателю для анализа в качестве упражнения.</p><empty-line/><p id=""></p><p>
function validateForm(){</p><p>
  var email = document.forms.tutform.elements.email.value;</p><p>
  if(!(/^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.</p><p>
     [a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/.test(email))){</p><p>
    alert('Пожалуйста, введите допустимый адрес e-mail');</p><p>
    return false;</p><p>
  }</p><p>
  return true;</p><p>
}</p><p>
</p><empty-line/><p>Как можно видеть, использование регулярного выражения приводит к более короткому (и более надежному) коду проверки, но он является и существенно более сложным!</p><p>С помощью примеров этой лекции теперь можно создать одну функцию для проверки всей формы:</p><empty-line/><p id=""></p><p>
function tut7(){</p><p>
  var form_object = document.forms.tutform;</p><p>
  var radios      = document.forms.tutform.elements.color;</p><p>
  var email       = document.forms.tutform.elements.email.value;</p><p>
</p><p>
  if(form_object.elements.firstname.value == "){</p><p>
    alert('Вы должны ввести свое имя!');</p><p>
    return false();</p><p>
  } else if(form_object.elements.lastname.value == "){</p><p>
    alert('Вы должны ввести свою фамилию!');</p><p>
    return false();</p><p>
  } else if(email.indexOf('@')&lt;0){</p><p>
    alert('В адресе e-mail должен быть символ @');</p><p>
    return false();</p><p>
  } else if(email.indexOf('@') != email.lastIndexOf('@')){</p><p>
    alert('В адресе e-mail не может быть более одного символа @');</p><p>
    return false();</p><p>
  } else if(email.indexOf('.')&lt;0){</p><p>
    alert('В адресе e-mail должна быть как минимум одна точка');</p><p>
    return false();</p><p>
  } else if(email.lastIndexOf('.')&lt;email.indexOf('@')){</p><p>
    alert('В адресе e-mail должна быть как минимум одна точка после символа @');</p><p>
    return false();</p><p>
  }</p><p>
</p><p>
  for(var i=0; i&lt;radios.length; i++){</p><p>
    if(radios[i].checked) return true();</p><p>
  }</p><p>
  alert('Необходимо выбрать цвет!');</p><p>
</p><p>
  return false;</p><p>
}</p><p>
</p><p>
</p><empty-line/></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="4.lecture"><title><p>Лекция 4.
 Функции и концепция объектов</p></title><annotation>В этой лекции будут полностью рассмотрены функции и представлена концепция объектов в <emphasis>JavaScript</emphasis>.</annotation><section id="4.section.1"><p>В <a l:href="">предыдущей лекции</a>  мы рассмотрели основы работы с полями форм и немного познакомились с функциями. Если какие-то из этих понятий вызывают затруднения, то желательно еще раз прочитать <a l:href="">последнюю лекцию</a>.</p><p>Как мы уже знаем, функции в <emphasis>JavaScript</emphasis> используются для многократного выполнения одной и той же задачи. До сих пор функции всегда вызывались вручную с помощью скобок: <emphasis>myFunction()</emphasis>. Что, если потребуется вызвать функцию, когда пользователь выполняет определенную задачу?  В <emphasis>JavaScript</emphasis> можно соединить функцию практически с любым событием, которое может порождать пользователь. Давайте посмотрим это в действии и напишем функцию, которая подсчитывает, сколько раз пользователь щелкнул на странице.</p><empty-line/><p id=""></p><p>
&lt;script type="text/javascript"&gt;</p><p>
var clickCount = 0;</p><p>
function documentClick(){</p><p>
  document.getElementById('clicked').value = ++clickCount;</p><p>
}</p><p>
document.onclick = documentClick;</p><p>
&lt;/script&gt;</p><p>
</p><p>
</p><p>
</p><p>
Вы щелкнули на этой странице &lt;input id="clicked" size="3" onfocus="this.blur();" value="0"&gt; раз. </p><p>
</p><p>
</p><p>
Вы щелкнули на этой странице  раз. </p><p>
</p><empty-line/><p>В <a l:href="">предыдущей лекции</a>  оператор <emphasis>++</emphasis>  был применен только после переменной, как в случае <emphasis>clickCount++</emphasis>.  Однако в данном примере оператор <emphasis>++</emphasis>  используется перед переменной. В первом примере <emphasis>clickCount++</emphasis>, единица добавляется к переменной   <emphasis>clickCount</emphasis> после чтения ее значения. В случае <emphasis>++clickCount</emphasis> единица добавляется к переменной <emphasis>clickCount</emphasis> перед чтением ее значения. Так как в этом примере переменной <emphasis>clickCount</emphasis>  в начале присваивается значение <emphasis>0</emphasis>, то единицу к ней необходимо добавлять до задания значения поля ввода, поэтому использована запись <emphasis>++clickCount</emphasis>.</p><p>Предыдущий пример может показаться достаточно знакомым. Так же, как и раньше, определяется переменная и функция. Изменение состоит в том, что вместо вызова функции <emphasis>documentClick()</emphasis> код содержит указание, что функция должна выполняться всякий раз, когда пользователь щелкает на документе.  <emphasis>document.onclick</emphasis>   связывает функцию с событием документа <emphasis>onclick</emphasis> ("при щелчке").</p><p>Существует множество событий подобных <emphasis>onclick</emphasis>. Мы познакомимся с некоторыми из них, но наиболее распространенными являются: <emphasis>onclick</emphasis>,  <emphasis>onload</emphasis>,  <emphasis>onblur</emphasis>,  <emphasis>onfocus</emphasis>,  <emphasis>onchange</emphasis>,  <emphasis>onmouseover</emphasis>,  <emphasis>onmouseout</emphasis> и <emphasis>onmousemove</emphasis>. Функцию можно связать  с событиями любого объекта, такого, как изображение или поле ввода, а не только документа. Например, события <emphasis>onmouseover</emphasis> и <emphasis>onmouseout</emphasis> используются обычно с изображениями для создания эффекта изменения.</p><p>Можно также заметить, что ссылка на поле ввода делается другим образом. Ранее говорилось, что для указания поля необходимо использовать  <emphasis>document.forms.имяФормы.elements.имяПоляВвода</emphasis>.  Хотя этот способ прекрасно работает, это не всегда необходимо. В данном примере поле ввода действует просто как счетчик. Оно не находится внутри формы, и нам это и не нужно. Поэтому мы задаем для поля некоторый <emphasis>ID</emphasis> (идентификатор): <emphasis>id="clicked"</emphasis>. <emphasis>ID</emphasis> можно использовать для ссылки на любой объект на странице. <emphasis>ID</emphasis> должен быть уникальным на странице, поэтому если  имеется <emphasis>5</emphasis> полей ввода с <emphasis>ID</emphasis>, то все <emphasis>ID</emphasis> должны быть различны, даже если они только имеют вид <emphasis>"input1"--&gt;"input5"</emphasis>.</p><p>Поскольку это поле ввода используется как счетчик, то нежелательно, чтобы пользователи щелкали на нем и изменяли его значение. Здесь на помощь приходит другое связывание, <emphasis>onfocus</emphasis>, которое срабатывает, когда курсор перемещается на объект. Поэтому при щелчке на поле ввода или при перемещении на поле ввода с помощью клавиши <emphasis>Tab</emphasis> вызывается <emphasis>onfocus</emphasis>.</p><p>Событие <emphasis>onfocus</emphasis> имеет очень короткий код, но он также очень важен. В нем появляется ключевое слово <emphasis>this</emphasis>, которое важно понимать в <emphasis>JavaScript</emphasis>. Ключевое слово <emphasis>this</emphasis> указывает на тот объект, на котором выполняется код. В данном примере <emphasis>this</emphasis> указывает на поле ввода. Выражение <emphasis>this.blur()</emphasis>  "размывает" поле ввода, другими словами, заставляет его терять фокус ввода. Так как это происходит, как только пользователь активизирует поле ввода, то это делает "невозможным" изменение данных.</p><p>Если указатель <emphasis>this</emphasis> используется в функции, то он указывает на саму функцию. Если <emphasis>this</emphasis> используется в коде <emphasis>JavaScript</emphasis> вне функции, то он указывает на объект окна. Наиболее часто <emphasis>this</emphasis> используется для изменения свойства текущего объекта, как в примере выше, или для передачи текущего объекта функции.</p><p>Давайте посмотрим на другой пример:</p><empty-line/><p id=""></p><p>
&lt;script type="text/javascript"&gt;</p><p>
function showValue(obj){</p><p>
  alert('You Clicked On ' + obj.value);</p><p>
}</p><p>
&lt;/script&gt;</p><p>
</p><p>
&lt;input type="radio" name="fruit" onclick="showValue(this);" value="Яблоко"  &gt; Яблоко</p><p>
&lt;input type="radio" name="fruit" onclick="showValue(this);" value="Апельсин" &gt; Апельсин</p><p>
&lt;input type="radio" name="fruit" onclick="showValue(this);" value="Груша"   &gt; Груша </p><p>
&lt;input type="radio" name="fruit" onclick="showValue(this);" value="Банан"&gt; Банан </p><p>
</p><p>
Яблоко   Апельсин   Груша   Банан </p><p>
</p><empty-line/><p>Можно видеть, что событие <emphasis>onclick</emphasis> для каждой из этих радио-кнопок одинаково. Однако, если щелкнуть на каждой из них, то будут получены разные сообщения. Это связано с использованием <emphasis>this</emphasis>. Так как <emphasis>this</emphasis> указывает на каждую отдельную радио-кнопку, то каждая радио-кнопка передается в функцию <emphasis>showValue</emphasis> по отдельности.</p><p>Вернемся к функциям и рассмотрим передачу функции аргументов. В предыдущем примере <emphasis>obj</emphasis> является аргументом. Предполагается, что <emphasis>obj</emphasis> содержит указатель на поле ввода, на котором был произведен щелчок. В функцию можно передавать любое количество аргументов. Если потребуется <emphasis>10</emphasis> аргументов, то функция будет выглядеть следующим образом:</p><empty-line/><p id=""></p><p>
function myFunction(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10){</p><p>
  // здесь располагается код </p><p>
}</p><p>
</p><empty-line/><p>Во многих случаях может понадобиться функция, которой требуется определенное количество аргументов, но не всегда требуются все. В <emphasis>JavaScript</emphasis> не нужно передавать все <emphasis>10</emphasis> аргументов в функцию, которая объявлена с <emphasis>10</emphasis> аргументами. Если передать только первые <emphasis>3</emphasis>, то функция будет иметь только <emphasis>3</emphasis> определенных аргумента. Это необходимо учитывать при написании функций. Например, можно написать функцию, которой всегда требуются <emphasis>3</emphasis> первых аргумента, но следующие <emphasis>7</emphasis> являются необязательными:</p><empty-line/><p id=""></p><p>
function myFunction(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10){</p><p>
  // код с arg1</p><p>
  // код с arg2</p><p>
  // код с arg3</p><p>
  if(arg4){</p><p>
    // код с arg4</p><p>
  }</p><p>
</p><p>
  if(arg5 &amp;&amp; arg6 &amp;&amp; arg7){</p><p>
    // код с arg5, arg6 и arg7</p><p>
    if(arg8){</p><p>
      // код с arg8</p><p>
    }</p><p>
  }</p><p>
</p><p>
  if(arg9 || arg10){</p><p>
    // код с arg9 или arg10</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p>Можно видеть, что в коде выполняется простая проверка <emphasis>if(arg)</emphasis>. Если аргумент не передается в функцию, то при попытке использовать этот аргумент будет получено значение <emphasis>undefined</emphasis>. При использовании <emphasis>undefined</emphasis> в качестве логического (булевого) значения (<emphasis>true / false</emphasis>), как в операторах <emphasis>if</emphasis>, оно воспринимается как <emphasis>false</emphasis>.</p><p>Поэтому, если <emphasis>arg4</emphasis> не был передан в приведенном выше примере, то он является <emphasis>undefined</emphasis> и тело оператора <emphasis>if</emphasis> не выполняется.</p><p>Как быть, когда трудно определить, сколько потребуется аргументов? Можно иметь функцию, которая получает от <emphasis>1</emphasis> до <emphasis>n</emphasis> аргументов и выполняет с каждым из них одну и ту же задачу. На этот случай <emphasis>JavaScript</emphasis> имеет в каждой функции объект <emphasis>arguments</emphasis>. Объект  <emphasis>arguments</emphasis> содержит все аргументы функции:</p><empty-line/><p id=""></p><p>
function myFunction(){</p><p>
  for(var i=0; i&lt;arguments.length; i++){</p><p>
    alert(arguments[i].value);</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p>Этот код сообщит значение всех переданных ему объектов. Если передать <emphasis>100</emphasis> объектов, то будет получено <emphasis>100</emphasis> сообщений. Более полезной функцией было бы, возможно, скрытие/вывод всех переданных функции объектов.</p><p>Один из наиболее интересных аспектов <emphasis>JavaScript</emphasis> - идея о том, что функции являются объектами и могут передаваться как поле ввода, изображение или что-то еще, что может быть. Посмотрите, например, следующий код:</p><empty-line/><p id=""></p><p>
&lt;script type="text/javascript"&gt;</p><p>
function multiply(){</p><p>
  var out=1;</p><p>
  for(var i=0; i&lt;arguments.length; i++){</p><p>
    out *= arguments[i];</p><p>
  }</p><p>
</p><p>
  return out;</p><p>
}</p><p>
</p><p>
function add(){</p><p>
  var out=0;</p><p>
  for(var i=0; i&lt;arguments.length; i++){</p><p>
    out += arguments[i];</p><p>
  }</p><p>
</p><p>
  return out;</p><p>
}</p><p>
</p><p>
function doAction(action){</p><p>
  alert(action(1, 2, 3, 4, 5));</p><p>
}</p><p>
&lt;/script&gt;</p><p>
</p><p>
&lt;button onclick="doAction(multiply)"&gt;Test Multiply&lt;/button&gt;</p><p>
&lt;button onclick="doAction(add)"     &gt;Test Add&lt;/button&gt;</p><p>
</p><p>
</p><p>
Test Multiply            Test Add </p><p>
</p><empty-line/><p>В этом небольшом фрагменте кода происходит очень многое. Вначале  просто определяют две функции: <emphasis>multiply</emphasis> и <emphasis>add</emphasis>. Функция <emphasis>multiply</emphasis> просто перемножает  все переданные ей числа. Аналогично, функция <emphasis>add</emphasis> складывает все переданные ей числа. 
Тонкости начинаются при использовании действий <emphasis>onclick</emphasis> двух созданных кнопок. Можно видеть, что при щелчке на любой из двух кнопок в функцию <emphasis>doAction</emphasis> передается объект.  Ранее мы всегда передавали переменные или объекты <emphasis>HTML</emphasis> (такие, как поля ввода в предыдущем примере). В этом примере передаются функции. Функции можно передавать таким же способом, как и любой другой объект, и когда они передаются, их можно вызывать таким же способом, как и любую другую функцию. Изменяется только ее имя.</p><p>Таким образом функция <emphasis>doAction</emphasis> получает другую функцию в качестве аргумента! Если передается функция <emphasis>multiply</emphasis>, то функция <emphasis>doAction</emphasis> передает ей значения от <emphasis>1</emphasis> до <emphasis>5</emphasis>, и мы получаем в результате  <emphasis>120</emphasis>. Если в <emphasis>doAction</emphasis> передается функция <emphasis>add</emphasis>, то ей также передаются значения от <emphasis>1</emphasis> до <emphasis>5</emphasis>, и в результате мы получаем значение  <emphasis>15</emphasis>.</p><p>Это в действительности одно из наиболее мощных свойств <emphasis>JavaScript</emphasis>, и оно будет более подробно рассмотрено в следующих лекциях. Пока достаточно понять общий принцип.</p><p>Другим важным свойством  функций является возможность вложения их друг в друга.  <emphasis>JavaScript</emphasis> не поддерживает истинный объектно-ориентированный подход к проектированию, но это свойство обеспечивает очень похожие возможности.</p><p>Кроме вложения функций, важно отметить, что имеется несколько различных способов объявления функций:</p><empty-line/><p id=""></p><p>
function myFunction(){</p><p>
  function nestedFunction1(arg1, arg2, arg3){</p><p>
    alert(arg1+arg2+arg3);</p><p>
  }</p><p>
</p><p>
  var nestedFunction2 = function(arg1, arg2, arg3){</p><p>
    alert(arg1+arg2+arg3);</p><p>
  }</p><p>
</p><p>
  var nestedFunction3 = new Function('arg1, arg2, arg3', 'alert(arg1+arg2+arg3);');</p><p>
}</p><p>
</p><empty-line/><p>В этом примере функции <emphasis>nestedFunction1</emphasis>, <emphasis>nestedFunction2</emphasis> и <emphasis>nestedFunction3</emphasis> являются одинаковыми по своим возможностям. Единственное различие состоит в том, как они определяются. <emphasis>nestedFunction1</emphasis> объявлена, как это делалось раньше. Синтаксис для <emphasis>nestedFunction2</emphasis> немного отличается. Мы задаем для функции переменную <emphasis>this.nestedFunction2</emphasis>. Синтаксис этого объявления будет следующий  <emphasis>имяПеременной= function(аргументы){</emphasis>. Аналогично для функции <emphasis>nestedFunction3</emphasis> задается переменная для новой функции. Однако это объявление существенно отличается, так как мы определяем функцию с помощью строк. Третий вариант используется редко, но является очень полезным, когда используется.  Он позволяет создать строку, содержащую код выполняемой функции, а затем определить функцию с помощью этой строки.</p><p>В <a l:href="">следующей лекции</a>  будут рассмотрены массивы.</p></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="5.lecture"><title><p>Лекция 5.
 Строки, числа и массивы</p></title><annotation> Внутренняя работа присущих JavaScript объектов: строк, чисел и массивов.</annotation><section id="5.section.1"><p>До сих пор мы рассматривали языковые конструкции <emphasis>JavaScript</emphasis>: операторы <emphasis>if</emphasis>, циклы, функции и т.д. В этой лекции будет рассмотрена внутренняя работа некоторых присущих <emphasis>JavaScript</emphasis> объектов: строк, чисел и массивов.</p><section id="5.section.2"><p>В <emphasis>JavaScript</emphasis> строка является любым фрагментом текста. Как и многие другие объекты в <emphasis>JavaScript</emphasis>, строки можно определять несколькими различными способами:</p><empty-line/><p id=""></p><p>
var myString = 'Hello, World!';</p><p>
var myString = new String('Hello, World!');</p><p>
</p><empty-line/><p>Первый метод используется наиболее часто. Второй метод применяется редко и только  для гарантии, что получаемый объект является строкой. Например:</p><empty-line/><p id=""></p><p>
var n = 5;</p><p>
var s = new String(n*20);</p><p>
</p><empty-line/><p>В этом примере s будет строкой "<emphasis>100</emphasis>". Если просто задать <emphasis>s</emphasis> как <emphasis>n*20</emphasis>, то <emphasis>s</emphasis> будет содержать число <emphasis>100</emphasis>. Однако поскольку <emphasis>JavaScript</emphasis> является слабо типизированным языком, то эти различия не будут существенно влиять на то, что вы делаете.</p><p>Строковые объекты (<emphasis>var n = new String('Hello World')</emphasis>) технически являются в <emphasis>Internet Explorer</emphasis> более медленными при некоторых операциях, чем строковые литералы (<emphasis>var n = 'Hello World'</emphasis>). Однако это поведение совершенно противоположно в других браузерах. В любом браузере различие редко бывает настолько заметно, чтобы об этом беспокоиться.</p><p>Единственное важное различие состоит в том, что <emphasis>eval()</emphasis> не работает со строковыми объектами.</p><p>Что, если в строке имеется апостроф? Следующий код работать не будет:</p><empty-line/><p id=""></p><p>
var n = 'The dog took it's bone outside';</p><p>
</p><empty-line/><p>Легко видеть, что апостроф в "<emphasis>it's</emphasis> " заканчивает строку. Поэтому мы получаем строку "<emphasis>The dog took it</emphasis> ", за которой следует " <emphasis>s bone outside'</emphasis> ".  Это продолжение само по себе не является допустимым кодом <emphasis>JavaScript</emphasis> (или правильным грамматически, если на то пошло), поэтому будет получена ошибка.</p><p>Здесь можно сделать две вещи. Так как строка определяется с помощью одиночных или двойных кавычек, то можно задать строку с помощью двойных кавычек. Другая возможность состоит в экранировании апострофа. Чтобы экранировать символ, необходимо просто подставить перед ним символ  <emphasis>\</emphasis>. Символ <emphasis>\</emphasis> в этом контексте сообщает <emphasis>JavaScript</emphasis>, что следующий символ необходимо воспринимать в точности так, как он есть, в номинальном значении, а не как специальный символ.</p><empty-line/><p id=""></p><p>
var n = "The dog took it's bone outside";</p><p>
var n = 'The dog took it\'s bone outside';</p><p>
</p><empty-line/><p>Если в строке должен присутствовать символ  <emphasis>\</emphasis>, то он экранируется таким же образом: <emphasis>'\\'</emphasis>.</p><p>В <a l:href="">предыдущей лекции</a>  мы встречались с функциями <emphasis>indexOf</emphasis> и <emphasis>lastIndexOf</emphasis>. Напомним, что они делают. Функция <emphasis>indexOf</emphasis> возвращает число, определяющее первую позицию одной строки в другой. Если разыскиваемая строка не существует, то <emphasis>indexOf</emphasis> возвращает <emphasis>-1</emphasis>. Функция <emphasis>lastIndexOf</emphasis> идентична <emphasis>indexOf</emphasis>, но возвращает не первую позицию вхождения строки, а последнюю.</p><p>Тот факт, что функции <emphasis>indexOf</emphasis> и <emphasis>lastIndexOf</emphasis> возвращают <emphasis>-1</emphasis>, если строка не существует, является очень полезным и позволяет использовать эти функции для достаточно распространенной задачи -  проверки того, что одна строка существует внутри другой.</p><p>Существует несколько других полезных функций для работы со строками, которые мы перечислим и кратко поясним.</p><p><strong>
		[x].
        </strong><emphasis>charAt()</emphasis> сообщает, какой символ находится в определенной позиции строки. Поэтому <emphasis>'Test'.charAt(1) = 'e'</emphasis>.</p><p><strong>
		[x].
        </strong><emphasis>length</emphasis> сообщает длину строки . <emphasis>'Test'.length = 4</emphasis>.</p><p><strong>
		[x].
        </strong><emphasis>substring()</emphasis> выдает строку между двумя индексами. <emphasis>'Test'.substring(1, 2) = 'e'</emphasis>.</p><p><strong>
		[x].
        </strong><emphasis>substr()</emphasis> аналогична <emphasis>substring()</emphasis>, только второе число является не индексом, а длиной возвращаемой строки. Если это число указывает на позицию за пределами строки, то  <emphasis>substr()</emphasis> вернет существующую часть строки. <emphasis>'Test'.substr(1, 2) = 'es'</emphasis>;</p><p><strong>
		[x].
        </strong><emphasis>toLowerCase()</emphasis> и <emphasis>toUpperCase()</emphasis> делают то, что обозначают: преобразуют строку в нижний или верхний регистр символов соответственно. <emphasis>'Test'.toUpperCase() = 'TEST'</emphasis>;</p><p>Примеры всех приведенных выше функций:</p><empty-line/><p id=""></p><p>
alert('This is a Test'.indexOf('T'));     //  0</p><p>
alert('This is a Test'.lastIndexOf('T')); //  10</p><p>
alert('This is a Test'.charAt(5));        //  i</p><p>
alert('This is a Test'.length);           //  14</p><p>
alert('This is a Test'.substring(5, 9));  //  is a</p><p>
alert('This is a Test'.substr(5, 9));     //  is a Test</p><p>
alert('This is a Test'.toUpperCase());    //  THIS IS A TEST</p><p>
alert('This is a Test'.toLowerCase());    //  this is a test</p><p>
</p><empty-line/><p>Последней строковой функцией, которая будет рассмотрена, является <emphasis>eval()</emphasis>. <emphasis>eval()</emphasis> получает строку и выполняет строку, как если бы это был код <emphasis>JavaScript</emphasis>.</p><empty-line/><p id=""></p><p>
eval("alert('Hello, World!')");</p><p>
</p><empty-line/><p>В этом примере будет выведено сообщение <emphasis>"Hello, World!"</emphasis>, как если бы функция <emphasis>alert</emphasis> была написана обычным образом. Это может быть очень полезно, так как позволяет создать содержащую код строку, а затем ее выполнить.</p></section><section id="5.section.3"><p>Работа с числами в <emphasis>JavaScript</emphasis> происходит достаточно просто. В лекциях <a l:href=""> 1</a>  и <a l:href=""> 2</a>  было показано, как выполняются базовые арифметические операции, операторы <emphasis>++</emphasis> , <emphasis>--</emphasis>, а также <emphasis>*=</emphasis>,  <emphasis>+=</emphasis>,  <emphasis>/=</emphasis> и <emphasis>-=</emphasis>. Мы узнали,  что <emphasis>NaN</emphasis> означает "Не число" и что делает функция <emphasis>isNaN()</emphasis>. Осталось рассмотреть еще только несколько вещей.</p><p>Объект <emphasis>Math</emphasis> в <emphasis>JavaScript</emphasis> содержит функции, позволяющие сделать почти все, что можно сделать с числами помимо обычной арифметики. <emphasis>Math.PI</emphasis>, например, содержит просто число <emphasis>3.141592653589793</emphasis>.  В нем содержатся тригонометрические функции (<emphasis>sin</emphasis>, <emphasis>cos</emphasis>, <emphasis>tan</emphasis>, и т.д.), функции для округления чисел (<emphasis>Math.floor</emphasis> возвращает число, округленное с недостатком, <emphasis>Math.ceil</emphasis> возвращает число, округленное с избытком, а <emphasis>Math.round</emphasis> округляет число "нормально") и многие другие. Существует очень много функций, объяснять которые здесь не имеет смысла. Их всегда можно найти в подходящем справочнике. (Например, <a l:href="">http://www.devguru.com/technologies/javascript/10734.asp</a>)</p><p>Двумя наиболее распространенными задачами, связанными с числами, являются преобразование числа в строку и строки в число. Как уже говорилось, <emphasis>JavaScript</emphasis> является слабо типизированным языком, а это означает, что типы данных не имеют большого значения, но существуют некоторые случаи, когда надо быть уверенным, что имеется число или строка. Если надо сложить, например, <emphasis>5</emphasis> и число, которое вводит пользователь, то надо быть уверенным, что введено число, а не слово "<emphasis>Привет</emphasis> ".</p><empty-line/><p id=""></p><p>
var n = parseInt("3.14"); // 3</p><p>
var n = parseFloat("3.14") // 3.14</p><p>
</p><empty-line/><p>Функция <emphasis>parseInt</emphasis> возвращает целое значение своего аргумента. Аргументы "<emphasis>3.14</emphasis>", "<emphasis>3</emphasis>", "<emphasis>3.00001</emphasis>" и "<emphasis>3.9999</emphasis>" превратятся в значение <emphasis>3</emphasis>. Функция <emphasis>parseFloat</emphasis>, с другой стороны, возвращает также любое десятичное значение. Обе эти функции пытаются "очистить" данные перед возвращением числа. Например, <emphasis>parseInt</emphasis>("3a") вернет значение <emphasis>3</emphasis>.</p><p>Существует также несколько методов, которые можно использовать, когда надо преобразовать число в строку:</p><empty-line/><p id=""></p><p>
var n = 5;</p><p>
</p><p>
var m = n.toString();</p><p>
var m = n+'';</p><p>
var m = new String(n);</p><p>
</p><empty-line/><p>Как говорилось ранее, последний метод может быть немного непривычным, поэтому предполагается, что пользователь будет держаться от него в стороне, если только не понадобится использовать объект <emphasis>String</emphasis> для специальных целей. Предпочтительным методом является <emphasis>n.toString()</emphasis>, но необходимо отметить, что часто используется второй метод. Например, если имеется уведомление <emphasis>alert('Имеется ' + apples + ' яблок')</emphasis>, то число <emphasis>apples</emphasis> автоматически преобразуется в строку.</p><p>Если необходимо выполнить строковую операцию с переменной, то необходимо быть уверенным, что имеется строка. Если, например, имеется запись года из 4 цифр и ее надо преобразовать в 2 цифры:</p><empty-line/><p id=""></p><p>
var year = 2000;</p><p>
</p><p>
var sYear = year.toString();</p><p>
var year2 = sYear.substr(sYear.length-2);</p><p>
</p><empty-line/><p>Можно было бы также легко вычесть <emphasis>2000</emphasis> из этой даты, но что, если датой является <emphasis>1995</emphasis>? или  <emphasis>1800</emphasis>? или <emphasis>2700</emphasis> или просто <emphasis>5</emphasis>? В результате могли бы получиться совершенно неправильные даты, если вычесть <emphasis>2000</emphasis>  из каждой такой даты. Используемый метод всегда даст правильные две цифры года.</p></section><section id="5.section.4"><p>Массив является по сути списком элементов. Каждый элемент массива может быть чем угодно, но обычно они связаны друг с другом. Если, например, необходимо отследить <emphasis>30</emphasis> студентов класса, то можно создать массив студентов:</p><empty-line/><p id=""></p><p>
var students = new Array();</p><p>
students[0] = 'Sam';</p><p>
students[1] = 'Joe';</p><p>
students[2] = 'Sue';</p><p>
students[3] = 'Beth';</p><p>
</p><empty-line/><p>Как можно видеть, определить массив очень просто, так же, как и присвоить значения его элементам. Однако пример выше имеет слишком много кода для относительно небольшого результата. Нет ничего удивительного в том, что существует несколько методов для создания массива. Значительно более компактным будет следующий пример:</p><empty-line/><p id=""></p><p>
var students = ['Sam', 'Joe', 'Sue', 'Beth'];</p><p>
</p><empty-line/><p>Это  код создает точно такой же массив, что и предыдущий пример, но, как можно видеть, он значительно более компактный и ничуть не сложнее для понимания. Скобки (<emphasis>[</emphasis> и <emphasis>]</emphasis>) в этом примере сообщают коду, что будет создан массив. Простая запись <emphasis>var students = [];</emphasis> является тем же самым, что и запись  <emphasis>var students = new Array();</emphasis>. Правда, некоторые люди считают, что использование слова <emphasis>Array</emphasis> более  наглядно, чем запись <emphasis>[]</emphasis>, поэтому можно использовать любой метод записи.</p><p>Что можно теперь сделать с этим массивом студентов? Чтобы обратиться к любому элементу массива, необходимо знать его индекс. В первом примере можно видеть, что в скобках находятся числа <emphasis>(0-3)</emphasis>. Это индексы. Если требуется узнать имя третьего студента, то надо будет написать  <emphasis>alert(students[2]);</emphasis>. Почему <emphasis>2</emphasis>, а не <emphasis>3</emphasis>? Массивы в <emphasis>JavaScript</emphasis> начинают индексацию с <emphasis>0</emphasis>, а не с <emphasis>1</emphasis>. Поэтому первым элементом в нашем массиве будет  <emphasis>students[0]</emphasis>, вторым - <emphasis>students[1]</emphasis>,  сотым  - <emphasis>students[99]</emphasis>, и т.д. Для этого не существует никакой реальной причины, просто так устроен <emphasis>JavaScript</emphasis> и многие другие языки программирования. Некоторые другие языки используют в качестве первого индекса <emphasis>1</emphasis>.</p><p>Наиболее распространенной задачей при работе с массивами, помимо изменения его данных, является проверка его длины, обычно для того, чтобы можно было перебрать весь массив и выполнить некоторую задачу с каждым элементом.</p><empty-line/><p id=""></p><p>
var students = ['Sam', 'Joe', 'Sue', 'Beth'];</p><p>
var suffixes = ['1st', '2nd', '3rd', '4th'];</p><p>
</p><p>
for(var i=0; i&lt;students.length; i++){</p><p>
  alert(suffixes[i]+' студент --  '+students[i]);</p><p>
}</p><p>
</p><empty-line/><p>Важный момент, который необходимо знать о массивах, состоит в том, что каждый элемент массива может содержать любой произвольный объект. В этих примерах каждый элемент массива является строкой, но они могут быть также числами, объектами, функциями, даже другими массивами.   Электронная таблица (такая, как <emphasis>Excel</emphasis>) является хорошим примером массива, содержащего другие массивы. Прежде всего имеется массив столбцов. Каждый столбец будет в свою очередь содержать в себе  массив строк. Этот массив создается точно таким же образом, как и массив <emphasis>students</emphasis>:</p><empty-line/><p id=""></p><p>
var spreadsheet = [</p><p>
  ['A1', 'B1', 'C1', 'D1'],</p><p>
  ['A2', 'B2', 'C2', 'D2'],</p><p>
  ['A3', 'B3', 'C3', 'D3'],</p><p>
  ['A4', 'B4', 'C4', 'D4']</p><p>
];</p><p>
</p><empty-line/><p>Переносы строк в <emphasis>JavaScript</emphasis> обычно не имеют значения. В этом примере переносы строк используются для придания коду большей наглядности и не влияют  на код никаким образом.</p><p>Можно видеть, что здесь имеется <emphasis>5</emphasis> массивов. Четыре внутренних массива (или вложенных массива) содержатся в одном большом массиве, <emphasis>spreadsheet</emphasis>. Если потребуется узнать значение на пересечении второго столбца и третьей строки, то можно написать:</p><empty-line/><p id=""></p><p>
var col2 = spreadsheet[1];</p><p>
alert(col2[2]);</p><p>
</p><p>
// или </p><p>
</p><p>
alert(spreadsheet[1][2]);</p><p>
</p><empty-line/><p>Оба фрагмента кода делают одно и то же, выводят значение "<emphasis>C2</emphasis> ".</p><p>Существует несколько распространенных операций, которые выполняются с массивами. Первой является добавление элемента в конец массива. Вернемся к массиву <emphasis>students</emphasis>, который содержит в данный момент <emphasis>4</emphasis> элемента. Чтобы добавить новый элемент, надо просто задать значение для 5-го элемента:</p><empty-line/><p id=""></p><p>
var students = ['Sam', 'Joe', 'Sue', 'Beth'];</p><p>
</p><p>
students[4]               = 'Mike';</p><p>
students[students.length] = 'Sarah';</p><p>
students.push('Steve');</p><p>
</p><p>
// теперь массив содержит 7 элементов: ['Sam', 'Joe', 'Sue', 'Beth', 'Mike', 'Sarah', 'Steve']</p><p>
</p><empty-line/><p>Здесь также существует несколько способов для выполнения этой задачи. Первый метод, <emphasis>students[4]</emphasis>, используется редко, так как обычно неизвестно заранее в точности, сколько будет элементов. Поэтому применяется один из двух оставшихся методов. <emphasis>push</emphasis> является функцией, которая просто добавляет то, что получает, в конец массива, как и предыдущий метод, использующий свойство <emphasis>.length</emphasis>.</p><p>Не так часто, но иногда необходимо также удалить объект из массива. В этом случае задействуется функция <emphasis>splice</emphasis>, которая позволяет добавить или удалить любое количество элементов массива, но в данный момент мы собираемся использовать ее для удаления одного студента, <emphasis>Mike</emphasis>, который переехал в другой город:</p><empty-line/><p id=""></p><p>
var students = ['Sam', 'Joe', 'Sue', 'Beth', 'Mike', 'Sarah', 'Steve'];</p><p>
students.splice(4, 1);</p><p>
</p><empty-line/><p> <emphasis>Splice</emphasis> в этом примере получает два аргумента: начальный индекс и число элементов для удаления. Так как <emphasis>Mike</emphasis> является пятым студентом, то его индекс будет <emphasis>4</emphasis>. Будет удален только <emphasis>1</emphasis> студент, поэтому здесь используется <emphasis>1</emphasis>. В результате имеем массив с удаленным <emphasis>Mike</emphasis>:</p><empty-line/><p id=""></p><p>
['Sam', 'Joe', 'Sue', 'Beth', 'Sarah', 'Steve']; </p><p>
</p><empty-line/><p>Чаще всего точно неизвестно, где в массиве находится элемент. К сожалению, единственным способом выяснить это является перебор всех элементов массива. Можно написать  небольшой простой сценарий, который позволит легко добавлять или удалять студентов:</p><empty-line/><p id=""></p><p>
var students  = ['Sam', 'Joe', 'Sue', 'Beth'];</p><p>
</p><p>
function addStudent(name){</p><p>
  students.push(name);</p><p>
}</p><p>
</p><p>
function removeStudent(name){</p><p>
  for(var i=0; i&lt;students.length; i++){</p><p>
    if(students[i].toLowerCase() == toLowerCase(name)){</p><p>
      students.splice(i, 1);</p><p>
      break;</p><p>
    }</p><p>
  }</p><p>
}</p><p>
</p><p>
</p><p>
Имя студента:   </p><p>
</p><p>
Добавить этого студента</p><p>
Удалить этого студента</p><p>
</p><p>
Студенты:  </p><p>
</p><empty-line/><p>Единственным новым моментом здесь является слово <emphasis>break</emphasis>.  <emphasis>break</emphasis> останавливает выполнение кода любого цикла, в котором находится: цикла <emphasis>for</emphasis>, цикла <emphasis>do</emphasis> или <emphasis>switch</emphasis>. Поэтому в данном случае, когда удаляемый студент найден, мы прерываем цикл <emphasis>for</emphasis>, так как выполнили свою задачу.</p><p>Часто бывает необходимо преобразовать массив в строку или строку в массив. Имеется две функции, которые могут легко это сделать:  <emphasis>join</emphasis> и <emphasis>split</emphasis>. Функция <emphasis>join</emphasis> получает массив и  преобразует его в строку с помощью разделителя, заданного в <emphasis>join</emphasis>.  Функция <emphasis>split</emphasis> действует в обратном направлении и делает массив из строки, определяя новый элемент c помощью разделителя, заданного в <emphasis>split</emphasis>:</p><empty-line/><p id=""></p><p>
var myString = 'apples are good for your health';</p><p>
var myArray = myString.split('a');  </p><p>
              // строка myString разбивается на элементы на каждом найденном символе 'a'.</p><p>
alert(myArray.join(', '));          </p><p>
              // преобразуем myArray снова в строку с помощью запятой, </p><p>
              // так что можно видеть каждый элемент </p><p>
alert(myArray.join('a'));           </p><p>
             // теперь преобразуем myArray снова в строку  с помощью символа 'a', </p><p>
             // так что снова получается исходная строка </p><p>
</p><empty-line/><p>Еще две полезные функции для работы с массивами - <emphasis>pop</emphasis> и <emphasis>shift</emphasis>. Функция <emphasis>pop</emphasis> удаляет последний элемент из массива и возвращает его. Функция <emphasis>shift</emphasis> удаляет первый элемент из массива и возвращает его.</p><empty-line/><p id=""></p><p>
var students  = ['Sam', 'Joe', 'Sue', 'Beth'];</p><p>
</p><p>
while(students.length&gt;0){</p><p>
  alert(students.pop());</p><p>
}</p><p>
</p><empty-line/><p>К сожалению, при этом массив был уничтожен: он теперь пуст. Иногда именно это и надо сделать. Если требуется просто очистить массив, то проще всего задать его длину (<emphasis>length</emphasis>) равной <emphasis>0</emphasis>:</p><empty-line/><p id=""></p><p>
students.length = 0</p><p>
</p><empty-line/><p>Теперь массив пуст. Даже если снова задать длину массива больше <emphasis>0</emphasis>, все данные  в массиве уже будут уничтожены.</p><p>Все использованные до сих пор массивы называются "индексными массивами", так как  каждый элемент массива имеет индекс, который необходимо использовать для доступа к элементу. Существуют также "ассоциативные массивы", в которых каждый элемент массива ассоциирован с именем в противоположность индексу:</p><empty-line/><p id=""></p><p>
var grades = [];</p><p>
grades['Sam']  = 90;</p><p>
grades['Joe']  = 85;</p><p>
grades['Sue']  = 94;</p><p>
grades['Beth'] = 82;</p><p>
</p><empty-line/><p>Ассоциативные массивы действуют немного иначе, чем индексные. Прежде всего, длина массива в этом примере будет равна <emphasis>0</emphasis>. Как же узнать, какие элементы находятся в массиве? Единственный способ сделать это - использовать цикл  "<emphasis>for-in</emphasis> ":</p><empty-line/><p id=""></p><p>
for(student in grades){</p><p>
  alert("Оценка " + student + "будет: " + grades[student]);</p><p>
}</p><p>
</p><empty-line/><p>Синтаксис цикла <emphasis>for-in</emphasis> следующий: " <emphasis>for(item in object){</emphasis> ".  Цикл пройдет через все элементы в объекте, и элемент будет именем элемента. В данном случае элементом является "<emphasis>Sam</emphasis>", затем " <emphasis>Joe</emphasis>", " <emphasis>Sue</emphasis>" и " <emphasis>Beth</emphasis>".</p><p>Последнее замечание о массивах состоит в том, что в действительности можно объединять ассоциативные и индексные массивы, хотя это обычно не рекомендуется, так как может вызывать некоторые проблемы. При правильном использовании, однако, можно с успехом это применять.</p><empty-line/><p id=""></p><p>
var students = ['Sam', 'Joe', 'Sue', 'Beth'];</p><p>
</p><p>
students['Sam']  = 90;</p><p>
students['Joe']  = 85;</p><p>
students['Sue']  = 94;</p><p>
students['Beth'] = 82;</p><p>
</p><p>
alert('Всего имеется '+(students.length)+' студентов: '+students.join(', '));</p><p>
for(var i=0; i&lt;students.length; i++){</p><p>
  alert("Оценка " +students[i]+"будет: "+students[students[i]]);</p><p>
}</p><p>
</p><empty-line/><p>Хотя это может показаться немного сложным, здесь нет ничего такого, о чем не говорилось в этой лекции.</p><p>Теперь читатель должен достаточно хорошо понимать основные типы данных <emphasis>JavaScript</emphasis>: строки, числа и массивы. В <a l:href="">следующей лекции</a>  будет рассмотрена Объектная модель документа, или <emphasis>DOM</emphasis> (Document Object Model).</p></section></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="6.lecture"><title><p>Лекция 6.
 Объектная модель документа</p></title><annotation> Объектная модель документа или коротко DOM (Document Object Model). Функции document.forms, document.getElementById, document.createElement и некоторые другие, которые встроены в объект document.</annotation><section id="6.section.1"><p>Эта лекция посвящена Объектной модели документа, или коротко <emphasis>DOM</emphasis> (Document Object Model). <emphasis>DOM</emphasis> является просто специальным термином для "всего на Web-странице". Объектная модель включает каждую таблицу, изображение, ссылку, поле формы и т.д. на Web-странице. <emphasis>JavaScript</emphasis> позволяет манипулировать с любым элементом на странице в реальном времени. Можно скрывать или полностью удалять любой элемент, добавлять элементы, копировать их,  изменять такие  свойства, как цвет, ширина, высота, и т.д., а при некотором воображении можно даже реализовать функции перетаскивания, анимации и почти все остальное, что можно придумать.</p><p>Прежде всего, необходимо понять, что с точки зрения браузера страница <emphasis>HTML</emphasis> является точно тем же, что и документ <emphasis>XML</emphasis>.  Если читатель имеет опыт работы с <emphasis>XML</emphasis>, то сможет понять обработку <emphasis>DOM</emphasis> достаточно легко. Но в любом случае это в действительности не сложно. Существует прекрасный справочник по адресу (<a l:href="">http://www.devguru.com/technologies/xml_dom/index.asp</a>), который подробно описывает  каждый метод обработки <emphasis>DOM</emphasis>, но к концу этой лекции читатель в основном поймет, как это работает.</p></section><section id="6.section.2"><p>Те, кто знает, что такое документ <emphasis>XML</emphasis>, могут пропустить этот раздел. Остальным необходимо его прочитать.</p><p>Будем надеяться, что читатель в какой-то степени знаком с <emphasis>HTML</emphasis>. Это то, из чего состоит (почти) каждая Web-страница. Каждое изображение, ссылка, таблица, поле формы и т.д. имеют свой собственный тег. Ниже приведен пример простой страницы <emphasis>HTML</emphasis>:</p><empty-line/><p id=""></p><p>
&lt;HTML&gt;</p><p>
&lt;BODY&gt;</p><p>
&lt;table border="0" cellspacing="2" cellpadding="5"&gt;</p><p>
   &lt;tr&gt;</p><p>
      &lt;td colspan="2"&gt;&lt;img src="Greetings.jpg" id="greetingImg" /&gt;&lt;/td&gt;</p><p>
   &lt;/tr&gt;</p><p>
   &lt;tr&gt;</p><p>
      &lt;td&gt;</p><p>
         Добро пожаловать на мою страницу HTML!</p><p>
         &lt;br /&gt;</p><p>
         &lt;a href="somelink.html" id="myLink" &gt;Щелкните здесь!&lt;/a&gt;</p><p>
      &lt;/td&gt;</p><p>
      &lt;td&gt;&lt;img src="hello.jpg" id="helloImg" /&gt;&lt;/td&gt;</p><p>
   &lt;/tr&gt;</p><p>
&lt;/table&gt;</p><p>
&lt;/BODY&gt;</p><p>
&lt;/HTML&gt;</p><p>
</p><empty-line/><p>Это просто обычная страница <emphasis>HTML</emphasis>. Возможно, вы не знаете о том, что это также пример документа <emphasis>XML</emphasis>. Здесь нас интересует то, что каждый элемент является потомком и/или предком другого элемента. Первое изображение находится внутри тега <emphasis>TD</emphasis>, который находится внутри тегов <emphasis>TR</emphasis>, <emphasis>TABLE</emphasis>, <emphasis>BODY</emphasis> и <emphasis>HTML</emphasis>. Двигаясь в другом направлении, можно видеть, что тег <emphasis>BODY</emphasis> имеет одного "потомка" - тег <emphasis>TABLE</emphasis>. Этот тег <emphasis>TABLE</emphasis> имеет в качестве потомков два тега <emphasis>TR</emphasis> и т.д. По сути именно так мы  перемещаемся в документе <emphasis>XML</emphasis> или <emphasis>HTML</emphasis> <emphasis>DOM</emphasis> - двигаясь от потомка к предку или от предка к потомку.</p><section id="6.section.3"><p>Изображение может помочь лучше понять отношения предок-потомок в этом коде.</p><image l:href="#6__6-1_gif" alt="Блок-схема документа"/><p id="">Блок-схема документа</p><p>Необходимо также отметить атрибуты в некоторых из этих тегов. Например, тег <emphasis>TABLE</emphasis> (<emphasis>&lt;table border="0" cellspacing="2" cellpadding="5"&gt;</emphasis>) имеет <emphasis>3</emphasis> заданых атрибута: <emphasis>border</emphasis>, <emphasis>cellspacing</emphasis> и <emphasis>cellpadding</emphasis>. При изменении <emphasis>DOM</emphasis> часто бывает необходимо изменить эти атрибуты. Можно, например, изменить атрибут <emphasis>SRC</emphasis> тега <emphasis>IMG</emphasis>, чтобы изменить выводимое изображение. Это часто делают, например, для создания эффекта изменения изображения, на которое направлен указатель (<emphasis>rollover</emphasis>).</p></section><section id="6.section.4"><p>Теперь, имея общее представление о компоновке страницы, можно начинать ее модификацию. Начнем с создания простого эффекта изменения изображения:</p><empty-line/><p id=""></p><p>
&lt;img src="button_off.gif"</p><p>
   onmouseover="this.src='button_over.gif';" </p><p>
   onmousedown="this.src='button_down.gif';"</p><p>
   onmouseout ="this.src='button_off.gif';" </p><p>
   onmouseup  ="this.src='button_over.gif';"&gt;</p><p>
</p><empty-line/><p>В этом коде присутствуют 4 события изображения: <emphasis>onmouseover</emphasis>, <emphasis>onmousedown</emphasis>, <emphasis>onmouseout</emphasis> и <emphasis>onmouseup</emphasis>. Каждое из этих событий имеет присоединенный простой фрагмент кода <emphasis>JavaScript</emphasis>, который изменяет атрибут <emphasis>src</emphasis> изображения. Создавая три разных изображения, можно легко и быстро создать изображение с тремя сменяющими друг друга состояниями.</p></section><section id="6.section.5"><p>Одной из задач, которая становится все более распространенной в современных приложениях <emphasis>JavaScript</emphasis>, является возможность добавления или удаления элементов страницы. Предположим, что имеется форма, которая позволяет послать кому-нибудь ссылку.  Обычно используется одно поле ввода для адреса e-mail и второе - для имени получателя. Если требуется послать ссылку нескольким  адресатам, то либо придется посылать форму несколько раз, либо можно было бы разместить на странице более одного набора  полей имя/e-mail.  Но в этом случае мы все еще ограничены заданным числом контактов. Если имеется пространство для <emphasis>5</emphasis> контактов и необходимо послать ссылку <emphasis>20</emphasis> людям, то форму придется заполнять   <emphasis>4</emphasis> раза.</p><p><emphasis>JavaScript</emphasis> позволяет обойти эту проблему, делая возможным динамическое дополнение и удаление содержимого страницы:</p><empty-line/><p id=""></p><p>
1  var inputs = 0;</p><p>
2  function addContact(){</p><p>
3    var table = document.getElementById('contacts');</p><p>
4</p><p>
5    var tr    = document.createElement('TR');</p><p>
6    var td1   = document.createElement('TD');</p><p>
7    var td2   = document.createElement('TD');</p><p>
8    var td3   = document.createElement('TD');</p><p>
9    var inp1  = document.createElement('INPUT');</p><p>
10    var inp2  = document.createElement('INPUT');</p><p>
11  </p><p>
12    if(inputs&gt;0){</p><p>
13      var img     = document.createElement('IMG');</p><p>
14      img.setAttribute('src', 'delete.gif');</p><p>
15      img.onclick = function(){</p><p>
16        removeContact(tr);</p><p>
17      }</p><p>
18      td1.appendChild(img);</p><p>
19    }</p><p>
20</p><p>
21    inp1.setAttribute("Name", "Name" +inputs);</p><p>
22    inp2.setAttribute("Email", "Email"+inputs);</p><p>
23</p><p>
24    table.appendChild(tr);</p><p>
25    tr.appendChild(td1);</p><p>
26    tr.appendChild(td2);</p><p>
27    tr.appendChild(td3);</p><p>
28    td2.appendChild(inp1);</p><p>
29    td3.appendChild(inp2);</p><p>
30</p><p>
31    inputs++;</p><p>
32  }</p><p>
33  function removeContact(tr){</p><p>
34    tr.parentNode.removeChild(tr);</p><p>
35  }</p><p>
36  &lt;table&gt;</p><p>
37     &lt;tbody id="contacts"&gt;</p><p>
38        &lt;tr&gt;</p><p>
39        &lt;td colspan="3"&gt;&lt;a href="javascript:addContact();"&gt;Добавьте контакт&lt;/a&gt;&lt;/td&gt;</p><p>
40        &lt;/tr&gt;</p><p>
41        &lt;tr&gt;</p><p>
42           &lt;td&gt;&lt;/td&gt;</p><p>
43           &lt;td&gt;Name &lt;/td&gt;</p><p>
44           &lt;td&gt;Email&lt;/td&gt;</p><p>
45        &lt;/tr&gt;</p><p>
46     &lt;/tbody&gt;</p><p>
47  &lt;/table&gt;</p><p>
</p><empty-line/><p>Демонстрация</p><empty-line/><p id=""></p><p>
Добавьте контакт </p><p>
</p><p>
Name     Email</p><p>
</p><empty-line/><p>Возможно вам не приходилось ранее использовать  тег  <emphasis>TBODY</emphasis>. Многие браузеры автоматически добавляют этот тег в <emphasis>DOM</emphasis>, не сообщая об этом. Если необходимо изменить содержимое таблицы, то в действительности необходимо изменить содержимое <emphasis>TBODY</emphasis>. Во избежание возможных недоразумений мы просто добавили тег <emphasis>TBODY</emphasis>, чтобы  каждый мог бы его видеть.  Все это может показаться достаточно сложным, но здесь очень мало нового материала.</p><p>Прежде всего здесь имеется новая функция: <emphasis>document.createElement</emphasis>. Функция <emphasis>createElement</emphasis> создает задаваемый аргументом элемент.  Можно видеть,  что в строках сценария с 5 по 10 создается несколько элементов. В действительности создается новая строка <emphasis>TR</emphasis>, которая вставляется в таблицу в строках 37-46.  В результате новая строка <emphasis>TR</emphasis> будет выглядеть следующим образом:</p><empty-line/><p id=""></p><p>
&lt;tr&gt;</p><p>
   &lt;td&gt;</p><p>
      &lt;img src="delete.gif"&gt;</p><p>
   &lt;/td&gt;</p><p>
   &lt;td&gt;</p><p>
      &lt;input name="Name1"&gt;</p><p>
   &lt;/td&gt;</p><p>
   &lt;td&gt; </p><p>
      &lt;input name="Email1"&gt;</p><p>
   &lt;/td&gt;</p><p>
&lt;/tr&gt;</p><p>
</p><empty-line/><p>Другими словами, мы создали 7 элементов: 1 <emphasis>TR</emphasis>, 3 <emphasis>TD</emphasis>, 2 <emphasis>INPUT</emphasis> и 1 <emphasis>IMG</emphasis>. Тег <emphasis>IMG</emphasis> будет использоваться как изображение кнопки "<emphasis>Удалить</emphasis> ". Так как пользователь должен всегда видеть по крайней мере 1 строку ввода, то первую строку  удалить невозможно. Поэтому в 12 строке сценария проверяется, что создается первая строка.   
Если строка не первая, то добавляется изображение.</p><p>После создания всех этих элементов остается в действительности поместить их в документ. Каждый элемент на странице имеет встроенную функцию <emphasis>appendChild</emphasis>, которую можно использовать для добавления к этому элементу потомка. Когда добавляется потомок, то он добавляется как последний элемент, поэтому если таблица уже имеет в качестве потомков <emphasis>10</emphasis> тегов <emphasis>TR</emphasis> и добавляется еще один, то он будет добавлен как 11-ый тег <emphasis>TR</emphasis>.  Мы начинаем с получения ссылки на таблицу (строка 3). Затем мы добавляем <emphasis>TR</emphasis> к этой таблице (строка 24) и добавляем затем 3 <emphasis>TD</emphasis> (строки 25-27).  Второй и третий <emphasis>TD</emphasis> содержат поле ввода, поэтому мы добавляем эти поля ввода (28-29).</p><p>Вот и все! Теперь у нас есть новый элемент <emphasis>TR</emphasis>, и он находится на странице. Осталось пояснить еще пару моментов. Чтобы форма была обработана правильно, все поля ввода должны иметь различные имена. Поэтому мы задаем имя двух полей ввода на основе счетчика (21-22), а затем увеличиваем счетчик (31). Это делается с помощью еще одной новой функции <emphasis>setAttribute</emphasis>, которая имеет два параметра: имя атрибута и значение атрибута. Для нее существует дополнительная  функция <emphasis>getAttribute</emphasis>, которая имеет только один аргумент: имя атрибута, значение которого надо получить.</p><empty-line/><p id=""></p><p>
element.setAttribute("name", "elementName")       </p><p>
</p><empty-line/><p>по сути то же самое, что</p><empty-line/><p id=""></p><p>
element.name="elementName"</p><p>
</p><empty-line/><p>Однако задание атрибута непосредственно, как в предыдущем примере, может иногда вызывать некоторые проблемы для различных браузеров или для некоторых специфических атрибутов. Поэтому хотя любой метод обычно будет работать, предпочтительным является первый метод, использующий <emphasis>setAttribute</emphasis>.</p><p>Необходимо также позаботиться о кнопке удаления. Мы уже знаем, что кнопка удаления для первой строки полей не создается, но необходимо заставить ее работать для всех остальных. Это делается в строках кода 15-16. Здесь к изображению добавлена функция <emphasis>onclick</emphasis>, которая вызывает функцию <emphasis>removeContact</emphasis>, передавая  элемент <emphasis>TR</emphasis> в качестве единственного аргумента.</p><p>Взглянув на функцию <emphasis>removeContact</emphasis>, можно видеть, что сначала происходит обращение <emphasis>tr.parentNode</emphasis> к функции <emphasis>parentNode</emphasis>, которая является еще одной функцией для работы с <emphasis>DOM</emphasis>. Она просто возвращает порождающий элемент для текущего элемента. Если посмотреть на изображенное ранее дерево документа, то видно, что <emphasis>parentNode</emphasis> вернет элемент непосредственно над элементом, на котором он вызван. Поэтому, если вызвать <emphasis>parentNode</emphasis> на одиночном элементе <emphasis>A</emphasis> в этом дереве, то будет получена ссылка на элемент <emphasis>TD</emphasis> над ним.</p><p>Поэтому <emphasis>tr.parentNode</emphasis> возвращает ссылку на элемент <emphasis>TABLE</emphasis> над <emphasis>TR</emphasis>. Затем вызывается функция <emphasis>removeChild</emphasis> на этом элементе <emphasis>TABLE</emphasis>, которая просто удаляет у предка указанного потомка.</p><p>Взглянув еще раз на строку 34, можно теперь увидеть, что она просто говорит:  "<emphasis>Удалить элемент <emphasis>TR</emphasis> у его предка</emphasis> " или еще проще "<emphasis>Удалить элемент TR</emphasis>".</p></section><section id="6.section.6"><p>Ко всем потомкам элемента можно обратиться с помощью атрибута <emphasis>childNodes</emphasis>, который возвращает массив, содержащий все узлы потомки текущего элемента. Можно также использовать атрибуты <emphasis>firstChild</emphasis> и <emphasis>lastChild</emphasis> на любом элементе, чтобы получить ссылки на первый или на последний элемент.</p><p>Чтобы увидеть, как это работает, давайте напишем сценарий для раскраски чередующихся строк <emphasis>TR</emphasis> в таблице:</p><empty-line/><p id=""></p><p>
function setColors(tbody, color1, color2){</p><p>
  var colors  = [color1, color2];</p><p>
  var counter = 0;</p><p>
  var tr      = tbody.firstChild;</p><p>
</p><p>
  while(tr){</p><p>
    tr.style.backgroundColor = colors[counter++ % 2];</p><p>
    tr = tr.nextSibling;</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p>Демонстрация</p><empty-line/><p id=""></p><p>
Row 1</p><p>
Row 2</p><p>
Row 3</p><p>
Row 4</p><p>
Row 5</p><p>
Row 6</p><p>
</p><p>
</p><p>
Color #1:  Color #2:  Раскрасьте таблицу</p><p>
</p><empty-line/><p>При рассмотрении этого небольшого фрагмента кода мало что нужно пояснять в том, как  можно получить этот интересный небольшой эффект. Код начинается с получения ссылки на первый элемент <emphasis>TR</emphasis> в таблице с помощью метода <emphasis>firstChild</emphasis>.  Затем каждый <emphasis>TR</emphasis> раскрашивается по очереди двумя разными цветами, используя  <emphasis>tr.style</emphasis>. Цвет фона задается одним из двух цветов из массива <emphasis>colors</emphasis>. Если <emphasis>counter</emphasis> имеет четное значение, то цвет фона задается как <emphasis>color1</emphasis>. Иначе он задается как <emphasis>color2</emphasis>. Это реализуется с помощью оператора деления по модулю (<emphasis>%</emphasis>). Для тех, кто забыл, напомним, что операция вычисляет остаток при делении. <emphasis>5/2 = 2</emphasis> с остатком <emphasis>1</emphasis>. Поэтому <emphasis>5 % 2 (5 по модулю 2)  = 1</emphasis>.</p><p>Здесь не будет обсуждаться в данный момент изменение стилей, но достаточно сказать, что <emphasis>element.style</emphasis> предоставляет доступ ко всему, что можно задать с помощью таблицы стилей. Если нужно, например, задать стиль элемента, то можно прочитать/записать весь стиль с помощью <emphasis>element.style.cssText</emphasis>.</p><p>После задания цвета фона берется следующий элемент <emphasis>TR</emphasis> в таблице. Это делается с помощью функции <emphasis>nextSibling</emphasis>, которая возвращает следующий элемент в <emphasis>DOM</emphasis>, с тем же предком, что и текущий элемент. Если посмотреть на тег <emphasis>TABLE</emphasis>, то все его потомки являются элементами <emphasis>TR</emphasis>, поэтому <emphasis>nextSibling</emphasis> будет в цикле перебирать все элементы <emphasis>TR</emphasis>. Если отыскивается элемент <emphasis>TR</emphasis> с потомками, состоящими из элементов <emphasis>TD</emphasis>, то <emphasis>nextSibling</emphasis> будет циклически перебирать все элементы <emphasis>TD</emphasis>.  Когда элементов <emphasis>TR</emphasis> больше не останется, цикл автоматически закончится, так как <emphasis>TR</emphasis> будет неопределенным, что в <emphasis>JavaScript</emphasis> оценивается как <emphasis>false</emphasis>.</p><p>С целью рассмотрения оператора <emphasis>childNodes</emphasis> и функции <emphasis>getElementsByTagName</emphasis> перепишем приведенный пример немного по-другому:</p><empty-line/><p id=""></p><p>
function setColors(tbody, color1, color2){</p><p>
  var colors  = [color1, color2];</p><p>
</p><p>
  for(var i=0; i&lt;tbody.childNodes.length; i++){</p><p>
    tbody.childNodes[i].style.backgroundColor = colors[i % 2];</p><p>
  }</p><p>
}</p><p>
</p><p>
function setColors(tbody, color1, color2){</p><p>
  var colors  = [color1, color2];</p><p>
  var trs     = tbody.getElementsByTagName('TR');</p><p>
</p><p>
  for(var i=0; i&lt;trs.length; i++){</p><p>
    trs[i].style.backgroundColor = colors[i % 2];</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p>Обе эти функции делают то же самое, что и первая функция <emphasis>setColors</emphasis>, но написано это немного по-другому. Первая функция использует атрибут <emphasis>childNodes</emphasis>. Как ранее говорилось, <emphasis>childNodes</emphasis> содержит массив, элементами которого являются потомки. Поэтому  мы циклически перебираем  <emphasis>tbody.childNodes</emphasis> и изменяем цвет каждого потомка, которые все должны быть элементами <emphasis>TR</emphasis>.</p><p>Другая функция использует новую функцию <emphasis>getElementsByTagName</emphasis>, которая выдает массив всех элементов с указанным именем тега. Так как нам требуются все элементы <emphasis>TR</emphasis>, то мы просто передаем в функцию <emphasis>'TR'</emphasis> и получаем список всех элементов <emphasis>TR</emphasis> в таблице. После этого код почти идентичен предыдущей функции.</p></section><section id="6.section.7"><p>Работа с текстом немного отличается от работы с другими элементами <emphasis>DOM</emphasis>. Первое: каждый фрагмент текста на странице помещен в невидимый узел <emphasis>#TEXT</emphasis>. Поэтому следующий код <emphasis>HTML</emphasis></p><empty-line/><p id=""></p><p>
&lt;div id="ourTest"&gt;this is &lt;a href="link.html"&gt;a link&lt;/a&gt; and an image: &lt;img src="img.jpg"&gt;&lt;/div&gt;</p><p>
</p><empty-line/><p>имеет четыре корневых элемента: текстовый узел со значением "<emphasis>this is</emphasis> ", элемент <emphasis>A</emphasis>, еще один текстовый узел со значением " <emphasis>and an image:</emphasis> " и,  наконец, элемент <emphasis>IMG</emphasis>. Элемент <emphasis>A</emphasis> имеет конечный текстовый узел в качестве потомка со значением " <emphasis>a link</emphasis> ".       
Когда необходимо изменить текст, то прежде всего необходимо получить этот "невидимый" узел. Если мы хотим изменить текст   " <emphasis>and an image:</emphasis> ", то необходимо написать:</p><empty-line/><p id=""></p><p>
document.getElementById('ourTest').childNodes[2].nodeValue = 'our new text';</p><p>
</p><empty-line/><p><emphasis>document.getElementById('ourTest')</emphasis> дает нам тег <emphasis>div. childNodes[2]</emphasis> дает узел текста " <emphasis>and an image:</emphasis> " и наконец <emphasis>nodeValue</emphasis> изменяет значение этого узла текста.</p><p>Что, если требуется добавить к этому еще текст, но не в конце, а перед " <emphasis>a link</emphasis> "?</p><empty-line/><p id=""></p><p>
var newText = document.createTextNode('our new text');</p><p>
var ourDiv  = document.getElementById('ourTest');</p><p>
ourDiv.insertBefore(newText, ourDiv.childNodes[1]);</p><p>
</p><empty-line/><p>Первая строка показывает, как создать текст с помощью <emphasis>document.createTextNode</emphasis>.
Это аналогично функции использованной ранее функции <emphasis>document.createElement</emphasis>. Третья строка содержит еще одну новую функцию <emphasis>insertBefore</emphasis>, которая аналогична <emphasis>appendChild</emphasis>, за исключением того, что имеет два аргумента: добавляемый элемент и  существующий элемент, перед которым надо сделать вставку. Так как мы хотим добавить новый текст перед элементом <emphasis>A</emphasis>  и знаем, что элемент <emphasis>A</emphasis> является вторым элементом в <emphasis>div</emphasis>, то мы используем <emphasis>ourDiv.childNodes[1]</emphasis> в качестве второго аргумента для <emphasis>insertBefore</emphasis>. </p><p>По большей части это все манипуляции с <emphasis>DOM</emphasis>. Если требуется создать, например, поле с изменяемым размером, то для изменения ширины и высоты поля будут использоваться те же функции мыши и функции <emphasis>getAttribute</emphasis> и <emphasis>setAttribute</emphasis>.  Очень похожим образом, если изменять верхнюю и левую позицию стиля элемента, то можно перемещать элементы по странице, либо в ответ на ввод мыши (перетаскивание), либо по таймеру (анимация).</p><p>В качестве последнего замечания к этой лекции: одним из наиболее полезных средств при попытке протестировать или отладить код <emphasis>JavaScript</emphasis>, который изменяет <emphasis>DOM</emphasis>, является сценарий обхода дерева <emphasis>DOM</emphasis>. Проще говоря - это сценарий, который показывает каждый элемент и каждый атрибут объекта <emphasis>DOM</emphasis>.  Описание этого кода выходит за рамки этой лекции, но он мог бы, например, показывать все атрибуты и объекты-потомки любого получаемого в качестве аргумента объекта.</p><p>Теперь можно включить свое воображение и экспериментировать, так как почти нет ничего такого, чего нельзя сделать со страницей <emphasis>HTML</emphasis>, когда вы знаете, как обращаться с <emphasis>DOM</emphasis>.  В  <a l:href=""> следующей лекции</a>  будут рассмотрены объекты окна и документа.</p></section></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="7.lecture"><title><p>Лекция 7.
 Объект документа и объект окна</p></title><annotation>Объект документа (document) и объект окна (window).
Функции setTimeout и setInterval, window.opener, document.body и 
document.documentElement. Cвойства документа  title, referer и cookies.</annotation><section id="7.section.1"><p>В <a l:href="">предыдущей лекции</a>  рассматривалось использование объекта документа. Были показаны функции <emphasis>document.forms</emphasis>, <emphasis>document.getElementById</emphasis>, <emphasis>document.createElement</emphasis> и некоторые другие, которые встроены в объект <emphasis>document</emphasis>. В этой лекции будут подробно рассмотрены объект документа (<emphasis>document</emphasis>) и объект окна (<emphasis>window</emphasis>), которые обладают многими полезными функциями.</p><p>Объект <emphasis>document</emphasis> представляет реальное содержимое страницы и поэтому имеет функции, которые помогают изменить саму страницу. Например, запись на странице происходит с помощью <emphasis>document.write</emphasis>, а обращение к форме - с помощью <emphasis>document.forms</emphasis>.</p><p>Как упоминалось в <a l:href="">шестой лекции</a>, каждый объект на  странице является потомком или предком какого-то другого объекта. Все это представляет большое дерево. Объект <emphasis>window</emphasis> находится в вершине этого дерева, а все остальное содержится в нем. Объект <emphasis>window</emphasis> указывает на реальное окно браузера. Если требуется, например, открыть новое окно или изменить размер текущего, то для этого используются функции объекта <emphasis>window</emphasis>.</p><p>Объект <emphasis>window</emphasis>, кроме того, что находится в вершине <emphasis>DOM</emphasis>, является также глобальным объектом. Во <a l:href="">второй лекции</a>  мы говорили о том, что любая переменная обладает глобальной или локальной областью действия. Если она имеет глобальную  область действия, то она доступна в любом месте сценария <emphasis>JavaScript</emphasis>. Обладание глобальной областью действия означает также, что переменная соединена непосредственно с объектом <emphasis>window</emphasis>. Любой код <emphasis>JavaScript</emphasis>, который не находится внутри какой-то функции, находится в глобальном объекте <emphasis>window</emphasis>.</p><p>В связи с этим не требуется писать <emphasis>window</emphasis> при обращении к функциям или  переменным объекта <emphasis>window</emphasis>, как в случае использования некоторых других функций, таких, как  <emphasis>document.getElementById.</emphasis> <emphasis>alert()</emphasis> является примером функции, которую можно вызвать либо как <emphasis>window.alert()</emphasis>, либо просто <emphasis>alert()</emphasis>.</p><section id="7.section.2"><p>Прежде всего объект <emphasis>window</emphasis> предоставляет доступ к информации об окне:</p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">Свойство</th><th valign="top" bgcolor="#d8d8d8">Описание</th></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>window.location</emphasis></td><td valign="top" bgcolor="#eaeaea">возвращает текущий <emphasis>URL</emphasis> окна</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>window.opener</emphasis></td><td valign="top" bgcolor="#eaeaea">Если окно было открыто другим окном (с помощью <emphasis>window.open</emphasis>), то возвращается ссылка на открывающее окно, иначе <emphasis>null</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>MSIE</emphasis>: <emphasis>window.screenTop</emphasis> Другие: <emphasis>window.screenY</emphasis></td><td valign="top" bgcolor="#eaeaea">Возвращает верхнюю позицию окна. Отметим, что эти значения в <emphasis>MSIE</emphasis> существенно  отличаются от других браузеров. <emphasis>MSIE</emphasis> возвращает верхнюю позицию области содержимого (ниже адресной строки, кнопок, и т.д.). Другие браузеры возвращают верхнюю позицию реального окна (выше кнопки закрытия)</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>MSIE</emphasis>: <emphasis>window.screenLeft</emphasis> Другие: <emphasis>window.screenX</emphasis></td><td valign="top" bgcolor="#eaeaea">Возвращает левую позицию окна с такими же различиями, как и для  <emphasis>screenTop</emphasis> и <emphasis>screenY</emphasis></td></tr></table></p><p>Положение окна на экране пользователя редко бывает необходимо, но два других свойства, <emphasis>location</emphasis> и <emphasis>opener</emphasis>, будут очень полезны.  Свойство <emphasis>window.location</emphasis> выполняет две функции. Если изменить его с помощью <emphasis>JavaScript</emphasis>, например, <emphasis>window.location='http://www.htmlgoodies.com'</emphasis>, то браузер будет перенаправлен на эту страницу. Чтение <emphasis>window.location</emphasis> выдает адрес текущего документа. Зачем это нужно знать?  Обычно адрес страницы не нужен, но может потребоваться строка запроса или анкер. Возьмем, например, следующий <emphasis>URL</emphasis>:</p><p> <a l:href="">http://www.somesite.com/page.asp?action=browse&amp;id=5#someAnchor</a>. Этот <emphasis>URL</emphasis> можно разбить на три части:</p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><td valign="top" bgcolor="#eaeaea"><emphasis>URL</emphasis>:</td><td valign="top" bgcolor="#eaeaea">http://www.somesite.com/page.asp</td></tr><tr><td valign="top" bgcolor="#eaeaea">Строка запроса:</td><td valign="top" bgcolor="#eaeaea">action=browse&amp;id=5</td></tr><tr><td valign="top" bgcolor="#eaeaea">Анкер:</td><td valign="top" bgcolor="#eaeaea">someAnchor</td></tr></table></p><p>Так как <emphasis>window.location</emphasis> содержит всю эту информацию, то можно написать функцию, которая будет возвращать переменную querystring (строку запроса). Это аналогично <emphasis>request.querystring</emphasis> в <emphasis>ASP</emphasis> или <emphasis>$_GET</emphasis> в <emphasis>PHP</emphasis>, если вы знакомы с каким-либо из этих языков:</p><empty-line/><p id=""></p><p>
function queryString(val){</p><p>
  var q  = unescape(location.search.substr(1)).split('&amp;');</p><p>
</p><p>
  for(var i=0; i&lt;q.length; i++){</p><p>
    var t=q[i].split('=');</p><p>
    if(t[0].toLowerCase()==val.toLowerCase()) return t[1];</p><p>
  }</p><p>
  return '';</p><p>
}</p><p>
</p><empty-line/><p>Для предыдущего <emphasis>URL</emphasis> функция <emphasis>queryString('action')</emphasis> вернет <emphasis>'browse'</emphasis>. Мы видим здесь новую функцию  <emphasis>window.unescape</emphasis>. Функция <emphasis>unescape</emphasis>, а также ее дополнительная функция <emphasis>escape</emphasis>, используются  в соединении с <emphasis>window.location</emphasis>. При передаче данных в строке запроса она должна быть экранирована (escaped), чтобы она не влияла на саму строку запроса. Если, например, среди данных имеется знак амперсанд (<emphasis>&amp;</emphasis>), то необходимо его экранировать, чтобы можно было различить этот знак в данных и тот <emphasis>&amp;</emphasis>, который разделяет два различных значения. Функция <emphasis>escape</emphasis> подготавливает посылаемые данные для использования в качестве значения <emphasis>querystring</emphasis>,  поэтому она используется при задании <emphasis>window.location</emphasis>. Например:</p><empty-line/><p id=""></p><p>
window.location='/page.asp?name='+escape(SomeInputBox.value);</p><p>
</p><empty-line/><p>Функция <emphasis>unescape</emphasis> делает обратное и позволяет получить "нормальный" текст из <emphasis>window.location</emphasis>.</p><p>Вернемся к свойствам <emphasis>window</emphasis>, где имеется свойство <emphasis>opener</emphasis>. Это свойство используется в соединении с обычно используемой функцией <emphasis>window.open</emphasis>, которая позволяет открывать новое окно браузера и, для некоторых свойств управлять его выводом.  Блокировщики всплывающих окон очень часто будут препятствовать открытию окна с помощью <emphasis>window.open</emphasis>, если в этот процесс не вовлечен щелчок мышью. Поэтому, если в коде имеется вызов <emphasis>window.open</emphasis> и при этом пользователь не щелкает на ссылке или чем-то подобном, то скорее всего это не будет работать.</p><p>Функция <emphasis>window.open</emphasis> получает до <emphasis>3</emphasis> аргументов: <emphasis>URL</emphasis> окна, которое надо открыть, имя окна и свойства окна.</p><empty-line/><p id=""></p><p>
var newWindow=window.open('', 'newWindow', 'width=200,height=200');</p><p>
newWindow.document.write('Это окно будет закрыто через 2 секунды');</p><p>
setTimeout(function(){ newWindow.close(); }, 2000);</p><p>
</p><empty-line/><p>Третий аргумент <emphasis>window.open</emphasis> получает строку аргументов. Обычно используются следующие:</p><p><strong>
		[x].
        </strong><emphasis>width</emphasis>,  <emphasis>height</emphasis> - задают размеры окна;</p><p><strong>
		[x].
        </strong><emphasis>left</emphasis>,  <emphasis>top</emphasis> - задают положение окна на экране;  </p><p><strong>
		[x].
        </strong><emphasis>location</emphasis>,  <emphasis>menubar</emphasis>,  <emphasis>toolbar</emphasis>,  <emphasis>status</emphasis>,  <emphasis>titlebar</emphasis>,  <emphasis>scrollbars</emphasis> - эти параметры выводят/скрывают свои соответствующие "панели" на окне. Задайте <emphasis>yes</emphasis>, чтобы вывести соответствующую "панель";</p><p><strong>
		[x].
        </strong><emphasis>resizable</emphasis> - если задан как <emphasis>yes</emphasis>, то размер окна можно изменять.</p><p>Полное описание <emphasis>window.open</emphasis> можно увидеть в документации Mozilla.</p><p>Так как мы открываем пустое окно, то первый аргумент будет пустым. Для открытия страницы <emphasis>'test.html'</emphasis> вызов выглядел бы следующим образом: <emphasis>window.open ('test.html', 'TestWindow', 'width=200,height=200')</emphasis>.</p><p>В этом примере для объекта <emphasis>window</emphasis>, открываемого окна, задается переменная <emphasis>newWindow</emphasis>. В связи с этим для вывода содержимого в окне необходимо использовать <emphasis>newWindow.document.write</emphasis>.</p><p>Функция <emphasis>window.open</emphasis> также имеет свою противоположность, функцию  <emphasis>window.close</emphasis>. Однако эта функция может успешно вызываться только на окнах, созданных <emphasis>JavaScript</emphasis>. Если попробовать закрыть окно, созданное не <emphasis>JavaScript</emphasis>, то возможны два варианта: либо появится сообщение, говорящее, что сценарий пытается закрыть окно, либо браузер просто это проигнорирует.</p></section><section id="7.section.3"><p>Можно видеть, что в этом примере используется еще одна новая функция <emphasis>setTimeout</emphasis>. Функции <emphasis>setTimeout</emphasis> и <emphasis>setInterval</emphasis> применяются для выполнения кода после указанного интервала времени и обе получают два аргумента:   функцию или строку кода и период ожидания в мс. <emphasis>1 мс = 1/1000 секунды</emphasis>, поэтому для задания выполнения кода через  <emphasis>5</emphasis> секунд необходимо определить в этом случае для второго аргумента  значение <emphasis>5000</emphasis>.</p><p><emphasis>setTimeout</emphasis> выполнит код один раз после завершения заданного интервала времени. <emphasis>setInterval</emphasis> будет продолжать выполнять код после завершения каждого интервала. При заданном интервале <emphasis>5000</emphasis>  <emphasis>setInterval</emphasis> будет выполнять код каждые <emphasis>5</emphasis> секунд.</p><p>Существуют еще две другие функции:  <emphasis>clearTimeout</emphasis> и <emphasis>clearInterval</emphasis>, которые отменяют  выполнение, через заданные интервалы. Однако для этого необходимо иметь ссылку на вызов <emphasis>setTimeout</emphasis> или <emphasis>setInterval</emphasis>, например:</p><empty-line/><p id=""></p><p>
var myTimeout = setTimeout("alert('Hi!');", 500);</p><p>
clearTimeout(myTimeout);</p><p>
</p><empty-line/><p>Если не сохранить ссылку в переменной <emphasis>myTimeout</emphasis>, то не существует способа отменить заданное выполнение. Давайте посмотрим на пример этого в действии:</p><empty-line/><p id=""></p><p>
function createTimeout(text, time){</p><p>
  setTimeout("alert('"+text+"');", time);</p><p>
}</p><p>
</p><p>
var intervals = [];</p><p>
function createInterval(text, time){</p><p>
  // сохраняет интервал в массиве intervals </p><p>
  intervals.push(setInterval("alert('"+text+"');", time));</p><p>
}</p><p>
</p><p>
function tut5(){</p><p>
  if(intervals.length==0) return;</p><p>
  // удаляет последний интервал выполнения в массиве intervals </p><p>
  clearInterval(intervals.pop());</p><p>
}</p><p>
</p><p>
</p><p>
Демонстрация в действии</p><p>
</p><p>
Текст для вывода:  </p><p>
</p><p>
Время ожидания(в мс):</p><p>
  </p><p>
setTimeout </p><p>
setInterval </p><p>
clearInterval </p><p>
</p><empty-line/><p>Существует также функция <emphasis>clearTimeout</emphasis>, которая идентична по синтаксису <emphasis>clearInterval</emphasis>.</p><p>Важно отметить, что во время ожидания выполнения заданного кода функциями <emphasis>setTimeout</emphasis> или <emphasis>setInterval</emphasis> весь остальной код <emphasis>JavaScript</emphasis> продолжает выполняться. Когда функция <emphasis>setTimeout</emphasis> или <emphasis>setInterval</emphasis> будет готова, она выполнит заданный код, но только после того, как другой код закончит выполнение. Другими словами,  <emphasis>setTimeout</emphasis> и <emphasis>setInterval</emphasis> никогда не прерывают для выполнения другой код.</p></section><section id="7.section.4"><p>Как говорилось ранее, свойство окна <emphasis> 'opener'</emphasis> можно использовать для доступа к окну, которое открыло текущее окно, а также к любым свойствам, функциям и т.д. этого окна. Например:</p><empty-line/><p id=""></p><p>
&lt;!--page1.html--&gt;</p><p>
&lt;HTML&gt;</p><p>
&lt;HEAD&gt;</p><p>
&lt;script type="text/javascript"&gt;</p><p>
window.open('page2.html', 'TestWindow', 'width=500,height=200,resizable=yes');</p><p>
&lt;/script&gt;</p><p>
&lt;/HEAD&gt;</p><p>
&lt;/HTML&gt;</p><p>
</p><p>
</p><p>
&lt;!--page2.html--&gt;</p><p>
&lt;HTML&gt;</p><p>
&lt;HEAD&gt;</p><p>
&lt;script type="text/javascript"&gt;</p><p>
document.write('URL окна предка будет : '+window.opener.location);</p><p>
&lt;/script&gt;</p><p>
&lt;/HEAD&gt;</p><p>
&lt;/HTML&gt;</p><p>
</p><empty-line/><p>Отметим, что это работает, только если <emphasis>URL</emphasis> открываемого окна находится на том же сервере, что и текущая страница. Если необходимо открыть, например, окно на <a l:href="">http://www.webreference.com</a>, то мы не получим доступ к свойствам этого окна. Это поддерживается всеми основными браузерами по соображениям безопасности.</p></section></section><section id="7.section.5"><p>Одной из наиболее часто используемых функций в <emphasis>JavaScript</emphasis> является <emphasis>document.write</emphasis>. Можно сказать, что <emphasis>document.write</emphasis> получает строку и выводит ее на странице. Здесь необходимо только следить за одной вещью. Если страница полностью загрузилась и вызывается <emphasis>document.write</emphasis>, то вся страница будет очищена и на экране будет только результат работы <emphasis>document.write</emphasis>.</p><p>Мы уже видели различные свойства объекта <emphasis>document</emphasis> в действии. Например, <emphasis>document.forms</emphasis> возвращает массив всех форм на странице. Здесь также существует несколько свойств, подобных этому.</p><p><strong>
		[x].
        </strong> <emphasis>document.forms</emphasis> - массив, содержащий все формы на текущей странице;</p><p><strong>
		[x].
        </strong> <emphasis>document.images</emphasis> - массив, содержащий все изображения на текущей странице;</p><p><strong>
		[x].
        </strong> <emphasis>document.links</emphasis> - массив, содержащий все  ссылки на текущей странице;</p><p><strong>
		[x].
        </strong> <emphasis>document.anchors</emphasis> - массив, содержащий все анкеры на текущей странице;</p><p><strong>
		[x].
        </strong> <emphasis>document.applets</emphasis> - массив, содержащий все апплеты на текущей странице;</p><p><strong>
		[x].
        </strong> <emphasis>document.styleSheets</emphasis> - массив, содержащий все таблицы стилей на текущей странице;</p><p><strong>
		[x].
        </strong> <emphasis>window.frames</emphasis> - массив, содержащий все фреймы на текущей странице.</p><p>Как мы видели в <a l:href="">предыдущей лекции</a>, почти все эти свойства можно продублировать с помощью <emphasis>document.getElementsByTagName</emphasis>. Чтобы получить все изображения на странице,  можно  воспользоваться, например,  <emphasis>document.getElementsByTagName('IMG');</emphasis>. Существует три подобные функции:</p><p><strong>
		[x].
        </strong> <emphasis>document.getElementById</emphasis> - возвращает один элемент на основе его <emphasis>ID</emphasis>;</p><p><strong>
		[x].
        </strong> <emphasis>document.getElementsByName</emphasis> - возвращает массив элементов, определенных по имени. В отличие от <emphasis>ID</emphasis> многие элементы могут иметь на странице одинаковые имена; </p><p><strong>
		[x].
        </strong> <emphasis>document.getElementsByTagName</emphasis> - возвращает массив элементов, определенных  по имени тега. Имя тега является просто именем тега <emphasis>HTML</emphasis>, т.е. <emphasis>'DIV'</emphasis>, <emphasis>'IMG'</emphasis>, <emphasis>'TABLE'</emphasis>, <emphasis>'A  '</emphasis>и т.д.</p><p>Существует еще одно свойство, <emphasis>document.all</emphasis>, которое выдает массив всех элементов на странице. Однако <emphasis>document.all</emphasis> поддерживается не всеми браузерами, поэтому предполагается, что вместо этого используется функция <emphasis>document.getElementsByTagName('*')</emphasis>, которая также вернет все элементы на странице.</p><section id="7.section.6"><p><emphasis>document.body</emphasis> ссылается на тег <emphasis>&lt;BODY&gt;</emphasis>, где должен предположительно находится весь контент. Весь <emphasis>DOM</emphasis> сайта вложен в <emphasis>document.body</emphasis>. Кроме этого, необходимо использовать  <emphasis>document.body</emphasis> для определения, что документ был прокручен, и для получения размера окна. К сожалению, это является одной из наиболее сложных вещей, применяемых сегодня в Web-браузерах.</p><p>Существует концепция, называемая "Тип документа", которая задает для Web-браузера определенный набор правил. Изменение типа документа заставляет некоторые свойства переместиться из  <emphasis>document.body</emphasis> в <emphasis>document.documentElement</emphasis>, но только некоторые свойства и только для некоторых браузеров.</p><p>Проще говоря, это является полным беспорядком, поэтому две следующие функции (будем надеятся) выдадут позицию прокручивания и размеры окна независимо от браузера.</p><empty-line/><p id=""></p><p>
function getScrollPos(){</p><p>
  if (window.pageYOffset){</p><p>
    return {y:window.pageYOffset, x:window.pageXOffset};</p><p>
  }</p><p>
  if(document.documentElement &amp;&amp; document.documentElement.scrollTop){</p><p>
    return {y:document.documentElement.scrollTop, x:document.documentElement.scrollLeft};</p><p>
  }</p><p>
  if(document.body){</p><p>
    return {y:document.body.scrollTop, x:document.body.scrollLeft};</p><p>
  }</p><p>
  return {x:0, y:0};</p><p>
}</p><p>
</p><p>
function getWindowDims(){</p><p>
  if (window.innerWidth){</p><p>
    return {w:window.innerWidth, h:window.innerHeight};</p><p>
  }</p><p>
  if (document.documentElement &amp;&amp; document.documentElement.clientWidth){</p><p>
    return {w:document.documentElement.clientWidth, h:document.documentElement.cliendHeight};</p><p>
  }</p><p>
  if (document.body){</p><p>
    return {w:document.body.clientWidth, h:document.body.clientHeight};</p><p>
  }</p><p>
  return {w:0, h:0}</p><p>
}</p><p>
</p><empty-line/></section><section id="7.section.7"><p>Тремя последними свойствами документа являются <emphasis>title</emphasis>, <emphasis>referer</emphasis> и <emphasis>cookies</emphasis>. <emphasis>document.title</emphasis> и <emphasis>document.referer</emphasis> достаточно понятны. <emphasis>document.title</emphasis> содержит заголовок страницы. Его можно прочитать и изменить после полной загрузки документа.  <emphasis>document.referer</emphasis>  содержит просто <emphasis>URL</emphasis> страницы, которая привела пользователя на текущую страницу.</p><p>Поэтому, если вы щелкнули на ссылке, чтобы попасть на эту страницу, то <emphasis>document.referer</emphasis> будет содержать <emphasis>URL</emphasis> страницы, на которой находится ссылка. Если вы пришли на эту страницу сразу, задавая ее в поле адреса браузера, то <emphasis>document.referer</emphasis> будет неопределен.</p></section><section id="7.section.8"><p>Последняя тема этой лекции, переменная <emphasis>cookie</emphasis>, отличается от всего остального в <emphasis>JavaScript</emphasis>. <emphasis>cookie</emphasis> является строкой текста, которую можно сохранить с одной страницы на другой, если вы находитесь на одном и том же сервере. В отличие от других переменных в <emphasis>JavaScript</emphasis>, <emphasis>cookie</emphasis> не стирается при  перезагрузке страницы. <emphasis>cookie</emphasis>  стираются только через определенный период времени или когда все <emphasis>cookie</emphasis> удаляются в браузере.</p><p><emphasis>cookie</emphasis> читают и записывают через <emphasis>document.cookie</emphasis>. В отличие от других свойств изменение <emphasis>document.cookie</emphasis> в действительности не перезаписывает, а добавляет к <emphasis>cookie</emphasis>.  Поэтому, если требуется задать <emphasis>5</emphasis> <emphasis>cookie</emphasis>, то каждое из них задается с помощью  <emphasis>document.cookie= "...";</emphasis>.  Формат <emphasis>cookie</emphasis> имеет свои особенности, поэтому мы рассмотрим несколько функций для выполнения этой задачи:</p><empty-line/><p id=""></p><p>
function writeCookie(name, value, days){</p><p>
  if(days){</p><p>
    (time = new Date()).setTime(new Date().getTime()+days*24*60*60*1000);</p><p>
    var exp = '; expires='+time.toGMTString();</p><p>
  }else{</p><p>
    var exp='';</p><p>
  }</p><p>
  document.cookie=name+"="+value+exp+"; path=/";</p><p>
}</p><p>
</p><p>
function readCookie(name){</p><p>
  var cookies = document.cookie.split(';');</p><p>
  for(var i=0; i&lt;cookies.length; i++){</p><p>
    var cookie=cookies[i].replace(/^\s+/, '');</p><p>
    if (cookie.indexOf(name+'=')==0) return cookie.substring(name.length+1);</p><p>
  }</p><p>
  return null;</p><p>
}</p><p>
</p><p>
function eraseCookie(name){</p><p>
  writeCookie(name, "", -1);</p><p>
}</p><p>
</p><empty-line/><p>Три эти функции выполняют запись, чтение и стирание <emphasis>cookie</emphasis> на текущей странице.  Их можно протестировать с помощью следующего кода:</p><empty-line/><p id=""></p><p>
function addToCounter(){</p><p>
  var counter = readCookie('myCounter');</p><p>
  if(counter){</p><p>
    counter = parseInt(counter);</p><p>
  } else {</p><p>
    counter = 0;</p><p>
  }</p><p>
</p><p>
  writeCookie('myCounter', counter+1, 1);</p><p>
}</p><p>
</p><p>
function showCounter(){</p><p>
  alert(readCookie('myCounter'));</p><p>
}</p><p>
</p><empty-line/><p>Если увеличить счетчик <emphasis>cookie</emphasis> несколько раз, обновить страницу, а затем проверить счетчик, то можно увидеть, что он остался таким же, как был до обновления страницы. Эти <emphasis>cookie</emphasis> будут сохранятся до тех пор, пока они не будут удалены из браузера или пока не пройдет 24 часа - <emphasis>cookie</emphasis> заданы на период одни сутки.</p><p>Это почти все об объектах окна и документа. В <a l:href="">следующей лекции</a>  речь пойдет об объектно-ориентированном коде.</p></section></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="8.lecture"><title><p>Лекция 8.
 Основы объектно-ориентированного программирования</p></title><annotation>Основы объектно-ориентированного программирования (ООП) в JavaScript. new Object и объектные литералы. Прототипирование. Переменные Private, Public и Static.</annotation><section id="8.section.1"><p>Почти каждый современный язык программирования имеет некоторый метод записи объектно-ориентированного (ОО) кода. Если вы знакомы с такими языками, как <emphasis>C++</emphasis>,  <emphasis>Java</emphasis>,  <emphasis>VB</emphasis>,  <emphasis>php</emphasis> или подобными, то должны быть знакомы и со структурой <emphasis>Class</emphasis> этих языков.</p><p>Классы в этих языках позволяют быстро создавать объекты с одинаковыми свойствами и методами, не требуя при этом заново определять все эти свойства и методы. В терминах структур мы имеем классы, а внутри этих классов - функции и переменные, а внутри каждой из этих функций - дополнительные переменные.  Каждая функция в классе идеально работает с переменными и другими функциями, внутренними для этого класса.</p><p>Структура <emphasis>Class</emphasis> и объекты в целом хорошо работают потому, что они действуют как реальные объекты. Например, мы можем иметь класс <emphasis>Телевизор</emphasis>. Так как все телевизоры в целом  работают одинаково, то нет необходимости переопределять множество атрибутов телевизора, чтобы сделать еще один новый. Этот класс будет определять методы и свойства телевизора. Мы будем иметь такие свойства, как марка, размер экрана, и т.д., и методы, такие, как включить/выключить, сменить канал, и т.д.</p><p><emphasis>JavaScript</emphasis> слегка отличается от стандартной объектно-ориентированной структуры <emphasis>Class</emphasis>. Вместо использования классов для создания объектов, каждая функция в <emphasis>JavaScript</emphasis> может эффективно действовать как класс. Мы используем концепцию вложенных функций, называемую прототипированием (<emphasis>Prototyping</emphasis>), для выполнения таких же вещей, как и языки со структурами <emphasis>Class</emphasis>. Если вы знакомы с ОО-языком на основе классов, то прототипирование может показаться сначала непривычной концепцией, но она предлагает большие возможности и часто является значительно более гибкой с точки зрения программирования, чем другие методы.</p><section id="8.section.2"><p>Для начала необходимо объяснить, как объекты действуют в  <emphasis>JavaScript</emphasis>. Объекты позволяют определить переменную и задать затем для этой переменной любое число свойств. Чтобы понять это, давайте посмотрим на простой пример:</p><empty-line/><p id=""></p><p>
var myObj  = new Object;</p><p>
myObj.a    = 5;</p><p>
myObj['b'] = 10;</p><p>
myObj.c    = 20;</p><p>
myObj.getTotal = function(){</p><p>
  alert(this.a+this.b+this.c);</p><p>
};</p><p>
</p><p>
// или </p><p>
</p><p>
var myObj = {a:5, b:10, c:20, </p><p>
 getTotal:function() { alert(this.a+this.b+this.c); }};</p><p>
</p><empty-line/><p>Оба эти фрагмента кода создают одну и ту же переменную <emphasis>myObj</emphasis>. Первый пример использует синтаксис <emphasis>new Object()</emphasis>, а затем определяет все свойства одно за другим.  Второй фрагмент кода является сокращенной нотацией, которая делает в точности то же самое.  Мы имеем теперь переменную <emphasis>myObj</emphasis>. <emphasis>myObj</emphasis> содержит три переменные для целых чисел: <emphasis>a</emphasis>,  <emphasis>b</emphasis> и <emphasis>c</emphasis>.  Для доступа к любой из них мы просто используем <emphasis>myObj.a</emphasis> или <emphasis>myObj['a']</emphasis>. Можно видеть, что <emphasis>myObj</emphasis> имеет также в качестве свойства функцию  <emphasis>getTotal</emphasis>. Мы обращаемся к <emphasis>getTotal</emphasis> таким же образом, как и к свойствам <emphasis>a</emphasis>,  <emphasis>b</emphasis> и <emphasis>c</emphasis>: <emphasis>myObj.getTotal()</emphasis>. Функция <emphasis>getTotal()</emphasis> обращается к переменным в переменной <emphasis>myObj</emphasis> с помощью <emphasis>this</emphasis>. При выполнении кода внутри функции в объекте <emphasis>this</emphasis>  ссылается на объект. В данном случае <emphasis>this</emphasis> ссылается на сам объект <emphasis>myObj</emphasis>.</p><p>Как можно видеть, объекты в <emphasis>JavaScript</emphasis> являются чрезвычайно полезными.  К сожалению,  часто приходится объявлять слишком много информации каждый раз, когда мы хотим создать объект. Например, давайте создадим объект <emphasis>Animal</emphasis>:</p><empty-line/><p id=""></p><p>
var myAnimal = {</p><p>
  name:     'felix',</p><p>
  species:  'cat',</p><p>
  talk:     function(){ alert('Meow!'); },</p><p>
  callOver: function(){ alert(this.name+' ignores you'); },</p><p>
  pet:      function(){ alert('Purr!'); }</p><p>
}</p><p>
</p><empty-line/><p>Мы имеем переменную <emphasis>myAnimal</emphasis>, которая представляет кота (<emphasis>cat</emphasis>) с именем <emphasis>Феликс</emphasis> (<emphasis>felix</emphasis>). Однако, если потребуется создать другого кота, нам понадобиться ввести все это снова. Здесь на помощь приходит объектно-ориентированный подход. Вместо перепечатки всякий раз всего объекта можно определить функцию, которая создает для нас аналогичный объект:</p><empty-line/><p id=""></p><p>
function Cat(name){</p><p>
  this.name     = name;</p><p>
</p><p>
  this.species  = 'Cat';</p><p>
  this.talk     = function(){ alert('Meow!'); }</p><p>
  this.callOver = function(){ alert(this.name+' ignores you'); },</p><p>
  this.pet      = function(){ alert('Purr!'); }</p><p>
}</p><p>
</p><p>
var felix = new Cat('Felix');</p><p>
var sam   = new Cat('Sam');</p><p>
var patty = new Cat('Patty');</p><p>
</p><p>
felix.pet();          // выводит 'Purr!'</p><p>
sam.callOver();       // выводит 'Sam ignores you'.  Просто, как кот!</p><p>
alert(patty.species); // выводит 'Cat'</p><p>
</p><empty-line/><p>В этом примере создана одна функция <emphasis>Cat</emphasis>, а затем  создаются три новых кота с помощью этой функции: <emphasis>Felix</emphasis>, <emphasis>Sam</emphasis> и <emphasis>Patty</emphasis>. Каждый из этих котов имеет одинаковые функции: <emphasis>talk</emphasis>, <emphasis>callOver</emphasis> и <emphasis>pet</emphasis>, и каждая из них имеет свойство <emphasis>species</emphasis>, заданное как <emphasis>'cat'</emphasis>.   И подобно всем котам, они в равной степени своенравны.</p><p>Обычно говорят, что <emphasis>felix</emphasis>, <emphasis>sam</emphasis> и <emphasis>patty</emphasis> являются экземплярами одного объекта: <emphasis>Cat</emphasis>. Код самой функции <emphasis>Cat</emphasis> называется конструктором. Мы передаем ей переменную <emphasis>name</emphasis> и используем ее для задания <emphasis>this.name</emphasis>. К сожалению, при объявлении каждой функции <emphasis>Cat</emphasis> в конструкторе в действительности создается новая копия каждой функции всякий раз при создании нового <emphasis>Cat</emphasis>. Так как функции <emphasis>talk</emphasis>, <emphasis>callOver</emphasis> и <emphasis>pet</emphasis> являются идентичными, то нам  в действительности требуется только одна копия каждой функции. Здесь на помощь приходит прототипирование.</p></section><section id="8.section.3"><p>Можно переписать функцию <emphasis>Cat</emphasis> таким образом, чтобы каждая функция объявлялась только один раз:</p><empty-line/><p id=""></p><p>
function Cat(name){</p><p>
  this.name = name;</p><p>
}</p><p>
Cat.prototype.species  = 'Cat';</p><p>
Cat.prototype.talk     = function(){ alert('Meow!'); };</p><p>
Cat.prototype.callOver = function(){ alert(this.name+' ignores you'); };</p><p>
Cat.prototype.pet      = function(){ alert('Purr!'); };</p><p>
</p><empty-line/><p>Синтаксис этого метода немного отличается от предыдущего.  Вместо объявления всех свойств и методов внутри функции <emphasis>Cat</emphasis>,  они теперь объявляются с помощью <emphasis>Cat.prototype</emphasis>. Это может показаться более сложным, но предлагает много преимуществ. Предположим, например, что надо добавить новую функцию <emphasis>sleep</emphasis> для каждого имеющегося <emphasis>cat</emphasis>. Это можно сделать двумя способами. Первый: можно добавить функцию <emphasis>sleep</emphasis> в <emphasis>felix</emphasis>, <emphasis>sam</emphasis> и <emphasis>patty</emphasis>. Это, однако, не только трудоемко, но также и неэффективно. Если бы имелось <emphasis>500</emphasis> <emphasis>cat</emphasis>, то потребовалось бы сначала отследить всех этих <emphasis>500</emphasis> котов, а затем добавить функцию каждому <emphasis>cat</emphasis>.</p><p>Однако с помощью прототипов можно добавить функцию <emphasis>sleep</emphasis> всем <emphasis>cat</emphasis> одновременно:</p><empty-line/><p id=""></p><p>
Cat.prototype.sleep = function(){ alert(this.name+' falls asleep'); };</p><p>
</p><empty-line/><p>Этот способ не только быстрее, но к тому же нам больше не требуется отслеживать каждого <emphasis>cat</emphasis>, чтобы добавить функцию <emphasis>sleep</emphasis>.</p><p>Существует более быстрый способ добавления прототипов. С помощью объектного литерала можно одновременно задать любое количество прототипов свойств или методов.</p><empty-line/><p id=""></p><p>
function Cat(name){</p><p>
  this.name = name;</p><p>
}</p><p>
Cat.prototype = {</p><p>
  species:  'Cat',</p><p>
  talk:     function(){ alert('Meow!'); },</p><p>
  callOver: function(){ alert(this.name+' ignores you'); },</p><p>
  pet:      function(){ alert('Pet!'); }</p><p>
}</p><p>
</p><empty-line/><p>Важно отметить, что с помощью этого метода можно задать свойства функции только один раз. После этого необходимо использовать предыдущий метод.</p><empty-line/><p id=""></p><p>
Object.prototype.method = function(){ ... }. </p><p>
</p><empty-line/><p>Если попробовать теперь добавить в <emphasis>cat</emphasis> метод <emphasis>sleep</emphasis> с помощью этого метода:</p><empty-line/><p id=""></p><p>
Cat.prototype = {</p><p>
  sleep: function(){ alert(this.name+' falls asleep'); }</p><p>
}</p><p>
</p><empty-line/><p>то предыдущие прототипы, <emphasis>species</emphasis>, <emphasis>talk</emphasis>, <emphasis>callOver</emphasis> и <emphasis>pet</emphasis>, будут все удалены. Единственным имеющимся прототипом для <emphasis>cat</emphasis> будет <emphasis>sleep</emphasis>.</p><p>Прототипы можно также использовать для расширения встроенных объектов <emphasis>JavaScript</emphasis>. Можно реализовать, например, функцию <emphasis>String.prototype.reverse</emphasis>, которая будет возвращать любую созданную строку в обратном порядке:</p><empty-line/><p id=""></p><p>
String.prototype.reverse = function(){</p><p>
  var out = '';</p><p>
  for(var i=this.length-1; i&gt;=0; i--){</p><p>
    out+=this.substr(i, 1);</p><p>
  }</p><p>
  return out;</p><p>
}</p><p>
alert('asdf'.reverse());</p><p>
</p><empty-line/><p>Это может быть очень полезным инструментом при правильном использовании. Можно реализовать <emphasis>String.prototype.trim()</emphasis> для удаления из строки всех пробелов, <emphasis>Date.prototype.dayName</emphasis> - для получения названия дня недели из объекта <emphasis>Date</emphasis> и т.д.  Однако настоятельно рекомендуется воздержаться от добавления каких-либо прототипов в <emphasis>Array</emphasis> или <emphasis>Object</emphasis>, так как в этом случае циклы <emphasis>for-in</emphasis> для двух этих типов данных будут работать неправильно. Рассмотрим следующий пример:</p><empty-line/><p id=""></p><p>
var myArray = [1, 2, 3];</p><p>
for(n in myArray) alert(n);  // выводит 0, 1 и 2 - индексы массива.</p><p>
</p><p>
Array.prototype.something = function(){ };</p><p>
</p><p>
for(n in myArray) alert(n);  // выводит 'something', 0, 1 и 2.</p><p>
</p><empty-line/><p>Как можно видеть, здесь выполнено прототипирование <emphasis>Array</emphasis> и добавлена функция <emphasis>something</emphasis>. Однако теперь эта функция <emphasis>something</emphasis> видна как элемент массива, результат, который определенно не ожидался и не требовался. То же самое происходит с объектами и объектными литералами, если выполнить прототипирование <emphasis>Object</emphasis>.     
Если можно быть абсолютно уверенным, что цикл <emphasis>for-in</emphasis> никогда не будет использоваться и никакой другой разработчик не будет использовать этот код <emphasis>JavaScript</emphasis>, то можно применять прототипирование для  <emphasis>Array</emphasis> или <emphasis>Object</emphasis>, но надо помнить о связанных с этим проблемах. Однако существуют другие методы для достижения тех же результатов.  Например, для расширения <emphasis>Array</emphasis> можно задействовать следующий метод без прототипирования:</p><empty-line/><p id=""></p><p>
Array.find = function(ary, element){</p><p>
  for(var i=0; i&lt;ary.length; i++){</p><p>
    if(ary[i] == element){</p><p>
      return i;</p><p>
    }</p><p>
  }</p><p>
  return -1;</p><p>
}</p><p>
</p><p>
alert(Array.find(['a', 'b', 'c', 'd', 'e'], 'b'));  // выводит 1</p><p>
</p><empty-line/><p>Как можно видеть, теперь необходимо печатать <emphasis>Array.find(ary, e)</emphasis>  вместо <emphasis>ary.find(e)</emphasis>, что пришлось бы делать, если прототипировать объект <emphasis>Array</emphasis>, но стоит напечатать  эти несколько дополнительных символов, чтобы избежать потери существующей функциональности <emphasis>JavaScript</emphasis>.</p></section><section id="8.section.4"><p>Способ определения переменных в объекте определяет, какие методы этого объекта можно использовать для доступа к этим переменным. В <emphasis>JavaScript</emphasis> при работе с объектно-ориентированным кодом используется пять уровней методов и свойств.</p><p><strong>1</strong> Скрытая (<emphasis>Private</emphasis>) - объявляется с помощью <emphasis>var variableName</emphasis> или <emphasis>function functionName</emphasis> внутри объекта. Могут быть доступны только другим скрытым или привилегированным функциям.</p><p><strong>2</strong> Открытая (<emphasis>Public</emphasis>) - объявляется с помощью <emphasis>this.variableName</emphasis> внутри объекта. Может изменяться любой функцией или методом.</p><p><strong>3</strong> Привилегированная (<emphasis>Privileged</emphasis>) - объявляется с помощью <emphasis>this.functionName = function(){ ... }</emphasis> внутри объекта. Доступна для любой функции или метода и может обращаться или изменять любую скрытую переменную.</p><p><strong>4</strong> Прототипированная (<emphasis>Prototype</emphasis>) - объявляется с помощью <emphasis>Class.prototype.variableName</emphasis> или <emphasis>Class.prototype.functionName</emphasis>. Объявленные таким образом функции будут иметь  доступ к любой открытой или прототипированной функции. Попытки изменить созданную таким образом переменную будут вместо этого создавать новую открытую переменную на объекте, а прототипированная переменная будет недоступна.</p><p><strong>5</strong> Статическая (<emphasis>Static</emphasis>) - объявляется с помощью <emphasis>Class.variableName</emphasis>  или <emphasis>Class.functionName</emphasis>. Может изменяться любой функцией или методом. Такой метод используется редко.</p><p>Чтобы понять различия между уровнями, давайте рассмотрим пример:</p><empty-line/><p id=""></p><p>
function Cat(name, color){</p><p>
  /*</p><p>
  Конструктор: при создании объекта выполняется любой находящийся здесь код </p><p>
  */</p><p>
  Cat.cats++;</p><p>
</p><p>
  /* Скрытые переменные и функции доступны только скрытым или привилегированным </p><p>
  функциям. Отметим, что  'name' и 'color', переданные в Class, уже являются </p><p>
  скрытыми переменными.</p><p>
  */</p><p>
</p><p>
  var age  = 0;</p><p>
  var legs = 4;</p><p>
  function growOlder(){</p><p>
    age++;</p><p>
  }</p><p>
</p><p>
  /*</p><p>
  Открытые переменные доступны открыто или скрыто </p><p>
  */</p><p>
</p><p>
  this.weight = 1;</p><p>
  this.length = 5;</p><p>
</p><p>
  /*</p><p>
  Привилегированные функции доступны открыто или скрыто. </p><p>
  Могут обращаться к скрытым переменным.</p><p>
</p><p>
  Невозможно изменить, можно только заменить открытой версией</p><p>
  */</p><p>
</p><p>
  this.age = function(){</p><p>
    if(age==0) this.length+=20;</p><p>
</p><p>
    growOlder();</p><p>
    this.weight++;</p><p>
  }</p><p>
}</p><p>
</p><p>
/*</p><p>
Прототипированные функции доступны открыто </p><p>
*/</p><p>
Cat.prototype = {</p><p>
  talk:     function(){ alert('Meow!'); },</p><p>
  callOver: function(){ alert(this.name+' ignores you'); },</p><p>
  pet:      function(){ alert('Pet!'); }</p><p>
}</p><p>
</p><p>
/*</p><p>
Прототипированные переменные доступны открыто.</p><p>
Нельзя перезаписать, только заменить открытой версией </p><p>
*/</p><p>
</p><p>
Cat.prototype.species = 'Cat';</p><p>
</p><p>
/*</p><p>
Статические переменные и функции доступны открыто </p><p>
*/</p><p>
</p><p>
Cat.cats = 0;</p><p>
</p><empty-line/><p>Мы видим, что существует несколько уровней доступа. Как было сказано ранее, все скрытые, привилегированные и открытые функции и переменные копируются всякий раз, когда создается новый экземпляр объекта. Обычно почти все, что нужно сделать, можно реализовать с помощью прототипированных и открытых переменных. В связи с этим обычно лучше избегать использования скрытых, привилегированных и статических переменных, если это не требуется специально.</p></section></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="9.lecture"><title><p>Лекция 9.
 Наследование и замыкание</p></title><annotation> Метод наследования. Полезные (и опасные) свойства замыкания.</annotation><section id="9.section.1"><p>В <a l:href="">восьмой лекции</a>  были рассмотрены основы объектно-ориентированного программирования в <emphasis>JavaScript</emphasis>. В данной лекции эта тема будет  продолжена рассмотрением методов наследования, а также полезных (и опасных) свойств замыкания.</p><section id="9.section.2"><p>В <a l:href="">предыдущей лекции</a>  была создана функция  <emphasis>'Cat'</emphasis> :</p><empty-line/><p id=""></p><p>
function Cat(name){</p><p>
  this.name = name;</p><p>
}</p><p>
Cat.prototype = {</p><p>
  species:  'Cat',</p><p>
  talk:     function(){ alert('Meow!'); },</p><p>
  callOver: function(){ alert(this.name+' ignores you'); },</p><p>
  pet:      function(){ alert('Pet!'); }</p><p>
}</p><p>
</p><empty-line/><p>Теперь можно создать любое количество котов, но как быть, если мы захотим создать объект другого типа, например, собаку? В этом случае понадобится создать совершенно новую функцию, со своими собственными прототипами. Если два объекта 
используют одни и те же функции (например, можно было бы добавить функции <emphasis>sleep</emphasis> (спать), <emphasis>eat</emphasis> (есть), и <emphasis>play</emphasis> (играть)), то в результате мы бы имели чрезмерное дублирование кода. Решением является концепция наследования.</p><p>По сути наследование позволяет определить объекты "предки" и "потомки". Потомок наследует все свойства своего предка. Можно было создать, например, функцию <emphasis>Animal</emphasis>, <emphasis>Pet</emphasis> или <emphasis>Mammal</emphasis>. Обе функции <emphasis>Cat</emphasis> и <emphasis>Dog</emphasis> обладали бы многими свойствами функции предка <emphasis>Animal</emphasis>, и нам пришлось бы писать этот код один раз.</p><p>Проблема в том, что <emphasis>JavaScript</emphasis> не имеет в действительности встроенного механизма наследования, поэтому эту функциональность необходимо создавать самостоятельно.  Для этого существует несколько различных способов. Один из них состоит в использовании функции <emphasis>call</emphasis>. Эта функция позволяет вызывать одну функцию из контекста другой, т.е.  мы можем определить, как действует ключевое слово <emphasis>this</emphasis>. С помощью <emphasis>call</emphasis> можно написать класс <emphasis>Animal</emphasis> (Животное), а затем вызвать его из класса <emphasis>Cat</emphasis> или <emphasis>Dog</emphasis>.</p><empty-line/><p id=""></p><p>
function Animal(name){</p><p>
  this.name = name;</p><p>
</p><p>
  this.species = 'Animal';</p><p>
  this.sleep   = function(){ alert(this.name+' спит: Хрррр'); }</p><p>
}</p><p>
function Cat(name){</p><p>
  Animal.call(this, name);</p><p>
</p><p>
  this.talk = function(){ alert('Мяу!'); }</p><p>
}</p><p>
function Dog(name){</p><p>
  Animal.call(this, name);</p><p>
</p><p>
  this.talk = function(){ alert('Гав!'); }</p><p>
}</p><p>
</p><p>
var sam = new Cat('Sam');</p><p>
var joe = new Dog('Joe');</p><p>
sam.sleep(); // Sam спит: Хрррр</p><p>
joe.sleep(); // Joe спит: Хрррр</p><p>
</p><p>
sam.talk();  // Мяу!</p><p>
joe.talk();  // Гав!</p><p>
</p><empty-line/><p>Хотя это работает, мы немного ограничены в своих возможностях. Например, прототипирование не действует при использовании этого метода: все прототипы, заданные на <emphasis>Animal</emphasis>, не будут переноситься в функции <emphasis>Cat</emphasis> или <emphasis>Dog</emphasis>. Как мы знаем из <a l:href="">предыдущей лекции</a>, определенные внутренне с помощью  "<emphasis>this.</emphasis>" функции создают новый экземпляр всякий раз при создании новой копии предка. В этом случае всякий раз при создании функции <emphasis>Animal</emphasis>, <emphasis>Cat</emphasis> или <emphasis>Dog</emphasis> появляется новая копия функций  <emphasis>species</emphasis> и <emphasis>sleep</emphasis>. Как можно догадаться, это не самый эффективный способ.</p><p>Лучшим подходом является прототипирование всего родительского класса на классе-потомке. Это предоставляет доступ ко всем свойствам и методам класса предка:</p><empty-line/><p id=""></p><p>
function Animal(name){</p><p>
  this.name = name;</p><p>
}</p><p>
Animal.prototype = {</p><p>
  species: 'Animal',</p><p>
  sleep  : function(){ alert(this.name+' спит: Хрррр'); }</p><p>
}</p><p>
</p><p>
function Cat(name){</p><p>
  Animal.apply(this, arguments);</p><p>
}</p><p>
Cat.prototype         = new Animal;</p><p>
Cat.prototype.species = 'Cat';</p><p>
Cat.prototype.talk    = function(){ alert('Мяу!'); }</p><p>
</p><p>
function Dog(name){</p><p>
  Animal.apply(this, arguments);</p><p>
}</p><p>
Dog.prototype         = new Animal;</p><p>
Dog.prototype.talk    = function(){ alert('Гав!'); }</p><p>
</p><p>
var sam = new Cat('Sam');</p><p>
var joe = new Dog('Joe');</p><p>
</p><p>
sam.sleep(); // Sam спит : Хрррр</p><p>
joe.sleep(); // Joe спит: Хрррр</p><p>
</p><p>
alert(sam.species); // Cat</p><p>
alert(joe.species); // Animal - для Dog функция species не определена </p><p>
</p><empty-line/><p>Можно продолжить это дальше и  создать отдельные функции для различных пород собак или кошек и т.д.</p></section><section id="9.section.3"><p>Замыкание (<emphasis>сlosure</emphasis>) является одним из наиболее мощных средств <emphasis>JavaScript</emphasis>.  Если воспользоваться простым объяснением, то замыкание связывает внутренние и внешние переменные в функции. Почему это так важно? Потому что замыкание позволяет эмулировать почти любое свойство любого языка программирования, даже если оно не существует в <emphasis>JavaScript</emphasis>. Это звучит немного непонятно, поэтому лучше начать с более простого примера:</p><empty-line/><p id=""></p><p>
function beginAdding(a){</p><p>
  a *= 5;</p><p>
  return function finishAdding(b){ alert(a+b); }</p><p>
}</p><p>
</p><p>
var add = beginAdding(10);</p><p>
</p><p>
add(20); // 70</p><p>
</p><empty-line/><p>Можно видеть, что в приведенном коде переменной <emphasis>'a'</emphasis> присваивается значение <emphasis>10</emphasis> и передается в функцию <emphasis>beginAdding</emphasis>, в то время как переменной <emphasis>'b'</emphasis> присваивается значение <emphasis>20</emphasis> и передается в функцию <emphasis>finishAdding</emphasis>.</p><p>А что содержится в переменной <emphasis>'add'</emphasis>? Она содержит функцию <emphasis>finishAdding</emphasis> с копией связанной с ней всей функции <emphasis>beginAdding</emphasis>. Копия переменной <emphasis>'a'</emphasis> из <emphasis>beginAdding</emphasis> сохраняется в памяти для дальнейшего использования.</p><p>Теперь, имея представление о замыкании, прежде чем продолжать, необходимо обсудить проблему утечки памяти. <emphasis>Internet Explorer</emphasis>, в частности,  подвержен достаточно неприятным утечкам памяти при использовании замыкания. Чтобы понять, почему необходимо знать о сборке мусора в <emphasis>Internet Explorer</emphasis>, посмотрим, как в этом браузере выполняется очистка памяти от ненужных объектов.</p><p><emphasis>Internet Explorer</emphasis> имеет два отдельных сборщика мусора: один для <emphasis>JavaScript</emphasis> и другой для объектов <emphasis>DOM</emphasis>. При выгрузке страницы браузер просматривает и удаляет весь код <emphasis>JavaScript</emphasis> и все объекты <emphasis>DOM</emphasis> со страницы. Утечка происходит, когда имеются циклические ссылки из объекта <emphasis>DOM</emphasis> в <emphasis>JavaScript</emphasis> и снова на объект <emphasis>DOM</emphasis> или из <emphasis>JavaScript--&gt;Dom--&gt;Javascript</emphasis>. <emphasis>Internet Explorer</emphasis> запутывается и не удаляет объекты при циклической ссылке.</p><empty-line/><p id=""></p><p>
var someInput    = document.getElementById('inputbox');</p><p>
var someFunction = function(){</p><p>
  alert(someInput.value);</p><p>
}</p><p>
</p><p>
someInput.onclick = someFunction;</p><p>
</p><empty-line/><p>Здесь представлен бесконечный цикл в терминах замыканий. Объект <emphasis>DOM</emphasis> <emphasis>someInput</emphasis> вовлечен в замыкание с  функцией <emphasis>someFunction</emphasis>  и наоборот. Браузер не может определить, что удалить в первую очередь, поэтому в результате имеем утечку памяти.</p><p>Замыкания создают, часто даже не осознавая этого. Возьмем, например, простую функцию:</p><empty-line/><p id=""></p><p>
function Animal(name){</p><p>
  this.sleep = function(){ alert(name+' спит: Хрррр'); }</p><p>
}</p><p>
</p><empty-line/><p>Можно не заметить этого, но переменная   <emphasis>'name'</emphasis>   в функции <emphasis>sleep</emphasis> приходит из родительской функции <emphasis>Animal</emphasis>. Это создает замыкание.</p><p>Даже определение простейшей функции может создавать замыкание:</p><empty-line/><p id=""></p><p>
var x = 5;</p><p>
var n = function(){</p><p>
  y=10;</p><p>
  return y;</p><p>
}</p><p>
</p><empty-line/><p>Здесь также создается замыкание, хотя на первый взгляд это не так. Почему? Когда мы создаем функцию, она получает доступ ко всем переменным в своей текущей области действия, поэтому мы создаем новую ссылку на переменную <emphasis>х</emphasis>.</p><p>Теперь мы подошли к понятию области действия. Каждая функция имеет свою область действия, в которой она выполняется. Все области действия кода сохраняются во внутреннем стеке памяти. Когда создается замыкание, оно получает доступ к одной из этих областей действия. Если создается несколько замыканий в одной и той же области действия, то каждое замыкание будет в действительности указывать на одинаковые копии каждой переменной области действия. Например:</p><empty-line/><p id=""></p><p>
var x       = 5;</p><p>
var alertX1 = function(){ alert(x); }</p><p>
</p><p>
x           = 10;</p><p>
var alertX2 = function(){ alert(x); }</p><p>
</p><p>
alertX1();</p><p>
alertX2();</p><p>
</p><empty-line/><p>Обе функции в этом случае выведут <emphasis>10</emphasis>. Почему? Потому что они обе указывают на одну и ту же копию <emphasis>х</emphasis>.</p><empty-line/><p id=""></p><p>
</p><p>
<image l:href="#9__scope1_png" alt=""/><p id=""/></p><p>
</p><p>
</p><empty-line/><p>Если изменить <emphasis>x</emphasis> в любой точке, то обе функции отразят это. Как это исправить? Проще всего изменить область действия замыкания:</p><empty-line/><p id=""></p><p>
function makeClosure(x){</p><p>
  return function(){ alert(x); }</p><p>
}</p><p>
</p><p>
var x       = 5;</p><p>
var alertX1 = makeClosure(x);</p><p>
</p><p>
x           = 10;</p><p>
var alertX2 = makeClosure(x);</p><p>
</p><p>
alertX1(); // 5</p><p>
alertX2(); // 10</p><p>
</p><empty-line/><p>Это решает проблему. Если, однако, этот код создавал утечку памяти, то утечка будет существенно больше, чем в предыдущем примере; и также используется больший объем памяти.  Оказывается, что в действительности имеется три различных области действия в этом простом примере:</p><empty-line/><p id=""></p><p>
<image l:href="#9__scope2_png" alt=""/><p id=""/></p><p>
</p><empty-line/><p>Можно видеть, что переменная <emphasis>х</emphasis> копируется в каждую из двух областей действия. Это связано с тем, что <emphasis>x</emphasis>  является строкой или числом. JavaScript всегда передает строки и числа по значению - то есть всегда делается копия переменной. С объектами все происходит иначе.  Если <emphasis>х</emphasis> является функцией, массивом или базовым объектом, то в этом случае ссылка в двух наших функциях происходит на одну и ту же копию <emphasis>x</emphasis>  и поэтому в результате выводимое сообщение будет одинаковым:</p><empty-line/><p id=""></p><p>
function makeClosure(x){</p><p>
  return function(){ alert(x.val); }</p><p>
}</p><p>
</p><p>
var x       = {val:5};</p><p>
var alertX1 = makeClosure(x);</p><p>
</p><p>
x.val       = 10;</p><p>
var alertX2 = makeClosure(x);</p><p>
</p><p>
alertX1(); // 10</p><p>
alertX2(); // 10</p><p>
</p><empty-line/><p>Отличие состоит в том, что <emphasis>x</emphasis>  теперь является объектом. Каждая из дополнительных областей действия указывает на одну и ту же копию <emphasis>x</emphasis>. При изменении значения <emphasis>x</emphasis>  оно изменяется в каждой области действия, в которой <emphasis>х</emphasis> упоминается.</p><p>Как избежать утечки памяти при использовании замыканий? Необходимо избегать использования циклических ссылок. Наиболее распространенной причиной утечки памяти является присоединение событий, таких, как событие <emphasis>onclick</emphasis>, к объектам <emphasis>DOM</emphasis>.</p><p>Часто совершенно невинный с виду код будет создавать утечку и ее бывает крайне сложно обнаружить. К счастью, протестировать наличие утечки памяти достаточно легко. Если при каждом обновлении страницы используемая память увеличивается, то приложение имеет утечку. Отследить, где это происходит, совершенно другая задача, но по крайней мере теперь известно о наличии проблемы!</p><p><a l:href="">Следующая лекция</a>  будет посвящен основам приложений <emphasis>AJAX</emphasis>!</p></section></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="10.lecture"><title><p>Лекция 10.
 Основы приложений AJAX</p></title><annotation>Основы приложений AJAX. Создание объекта XMLHttp.
Варианты получения данных:  XML, JSON или обычный текст. 
Пример со списком контактов.</annotation><section id="10.section.1"><p>В последнее время термин <emphasis>AJAX</emphasis> получил широкое распространение. По сути, это необычное название технологии, которая уже давно существует. Однако за последний год <emphasis>JavaScript</emphasis> в стиле <emphasis>AJAX</emphasis> стал очень популярным у многих разработчиков, и мы начинаем видеть, как с его помощью стали создавать различные интересные вещи. <emphasis>Google Maps</emphasis> и <emphasis>GMail</emphasis> являются двумя наиболее широко известными приложениями <emphasis>AJAX</emphasis>, но в последнее время и другие компании по всему миру начали использовать ее на своих сайтах.</p><p><emphasis>AJAX</emphasis> означает "<emphasis>Asynchronous JavaScript and XML</emphasis>", т.е. Асинхронный <emphasis>JavaScript</emphasis> и <emphasis>XML</emphasis>. В действительности <emphasis>AJAX</emphasis> состоит из <emphasis>JavaScript</emphasis>, как и любое другое приложение, и соединения <emphasis>XMLHTTP</emphasis> с <emphasis>Web-сервером</emphasis>.  Вот и все! Общая идея заключается в том, что можно извлекать с сервера данные просто по мере необходимости, не обновляя всю страницу.</p><p>Прежде всего <emphasis>AJAX</emphasis> почти всегда опирается на серверный язык, такой, как <emphasis>PHP</emphasis> или <emphasis>ASP</emphasis>.  Когда пользователю необходимо получить новые данные, <emphasis>JavaScript</emphasis> запрашивает их, а сервер, вероятно, запросит базу данных и затем вернет данные. Эти данные можно вернуть в различной форме. Если они структурированы, то это будут обычно данные <emphasis>XML</emphasis> или <emphasis>JSON</emphasis>. Если это очень простые данные (такие, как получение описания какого-то объекта), то можно часто увидеть людей, которые просто записывают эти данные непосредственно в ответ <emphasis>AJAX</emphasis>.</p><section id="10.section.2"><p>При создании запроса <emphasis>AJAX</emphasis> прежде всего необходимо создать объект <emphasis>XMLHTTP</emphasis>. 
<emphasis>Netscape/Firefox</emphasis>, <emphasis>Opera</emphasis> и другие браузеры имеют этот объект встроенным. <emphasis>Internet Explorer</emphasis> использует <emphasis>ActiveXObject</emphasis>. Поэтому мы создадим одну функцию для работы со всеми этими браузерами:</p><empty-line/><p id=""></p><p>
if(typeof(XMLHttpRequest)!='undefined'){</p><p>
  var getXMLHttpObj = function(){ return new XMLHttpRequest(); }</p><p>
} else {</p><p>
  var getXMLHttpObj = function(){</p><p>
    var activeXObjects = ['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0',</p><p>
    'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];</p><p>
    for(var i=0; i&lt;activeXObjects.length; i++){</p><p>
      try{</p><p>
        return new ActiveXObject(activeXObjects[i]);</p><p>
      }catch(err){}</p><p>
    }</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p>Любой браузер, который поддерживает объект <emphasis>XMLHttpRequest</emphasis>, будет использовать этот встроенный объект. <emphasis>Internet Explorer 6</emphasis>  и более ранние версии будут использовать объект <emphasis>ActiveX XMLHttp</emphasis> компании <emphasis>Microsoft</emphasis>. Существует много различных версий этого объекта, поэтому мы попробуем их все, начиная с самого нового.</p><p>Теперь, когда мы имеем объект <emphasis>XMLHttp</emphasis>, можно разместить запрос на сервере:</p><empty-line/><p id=""></p><p>
var oXml = getXMLHttpObj();</p><p>
oXml.open('GET', 'getData.php', true);</p><p>
oXml.onreadystatechange = processingFunction;</p><p>
oXml.send();</p><p>
</p><p>
function processingFunction(){</p><p>
  if(oXml.readyState!=4) return; // запрос не выполнен </p><p>
</p><p>
  // Результаты обрабатываются здесь.  Подробнее дальше!</p><p>
}</p><p>
</p><empty-line/><p>После создания объекта <emphasis>XMLHttp</emphasis> остается еще 4 дополнительных шага. Сначала определяются параметры соединения с помощью функции <emphasis>.open</emphasis>. Функция <emphasis>.open</emphasis> получает <emphasis>3</emphasis> аргумента: тип запроса, <emphasis>URL</emphasis> и флаг, который сообщает объекту, выполняться или нет асинхронно.</p><p>Первый аргумент, тип запроса, почти всегда будет <emphasis>GET</emphasis> или <emphasis>POST</emphasis>. Если извлекаются данные, то это будет обычно <emphasis>GET</emphasis>, а если отправляется форма с <emphasis>AJAX</emphasis>, то это часто будет <emphasis>POST</emphasis>.</p><p>Флаг асинхронности немного отличается почти от всего остального в <emphasis>JavaScript</emphasis>. Если этот флаг задан как <emphasis>false</emphasis>, то код продолжает выполняться, как и любой другой фрагмент кода, то есть он ожидает, пока объект <emphasis>XMLHttp</emphasis> завершит свою работу, прежде чем двигаться дальше. Однако, если этот флаг задан как <emphasis>true</emphasis>, то код продолжает делать то, что следует в коде после запроса. Когда состояние запроса изменяется, вызывается функция, которая определена в <emphasis>onreadystatechange</emphasis>.</p><p>В чем различие? Если флаг асинхронности  задан как <emphasis>false</emphasis>, то браузер будет полностью заблокирован, пока обрабатывается запрос. Если запрошенные данные нужны в обязательном порядке для продолжения работы, то используйте это значение флага. Если флаг задан как <emphasis>true</emphasis>, то пользователь может продолжать использовать Web-страницу, но ничего не известно о том, когда вернется ответ на запрос.  Может потребоваться <emphasis>1/2</emphasis> секунды или  <emphasis>1</emphasis> минута.  Все зависит от нагрузки на сервер и соединения конечного пользователя.</p><p>Когда все готово, посылается запрос. Затем мы ожидаем. Если запрос выполняется синхронно с функцией обработки, определенной с помощью <emphasis>onreadystatechange</emphasis>, то она будет вызываться несколько раз. На самом деле она вызывается всякий раз при изменении состояния запроса. Существуют различные состояния, такие, как отправка и загрузка данных, но нас интересует только завершение загрузки данных. Если <emphasis>readyState == 4</emphasis>, то запрос выполнен,  поэтому в любом другом случае мы просто выходим из функции.</p><p>Теперь мы получили данные, но что это за данные?</p></section><section id="10.section.3"><p>Существует три возможных варианта получения данных:  <emphasis>XML</emphasis>, <emphasis>JSON</emphasis> или обычный текст. При извлечении данных из базы данных, скорее всего, будет использоваться <emphasis>XML</emphasis> или <emphasis>JSON</emphasis>. Ни один из этих вариантов не имеет явных преимуществ. <emphasis>XML</emphasis> - широко распространенный стандарт, и поэтому существует много приложений, которые работают с файлами <emphasis>XML</emphasis>. <emphasis>JSON</emphasis> является более новой идеей, но быстро становится популярным. Его обычно легче прочитать (для человека), и он требует немного меньшую полосу пропускания для пересылки.</p><p>Предположим, что создается приложение для управления контактами. Cервер может возвращать информацию о людях. Одни и те же данные можно выразить в форме <emphasis>XML</emphasis> или <emphasis>JSON</emphasis>:</p><p><strong>XML:</strong></p><empty-line/><p id=""></p><p>
&lt;xml&gt;</p><p>
  &lt;contacts&gt;</p><p>
    &lt;person firstname="Joe" lastname="Smith" phone="555-1212" /&gt;</p><p>
    &lt;person firstname="Sam" lastname="Stevens" phone="123-4567" /&gt;</p><p>
  &lt;/contacts&gt;</p><p>
&lt;/xml&gt;</p><p>
</p><empty-line/><p><strong>JSON:</strong></p><empty-line/><p id=""></p><p>
{contacts:[</p><p>
  {"firstname":"Joe", "lastname":"Smith",   "phone":"555-1212"},</p><p>
  {"firstname":"Sam", "lastname":"Stevens", "phone":"123-4567"}</p><p>
]}</p><p>
</p><empty-line/><p>Можно видеть, что нотация <emphasis>XML</emphasis> выглядит очень похоже на <emphasis>HTML</emphasis>. По большей части это так и есть. <emphasis>HTML</emphasis> и <emphasis>XML</emphasis> оба являются основанными на тегах языками и могут даже анализироваться одинаковым образом (см. <a l:href="">Лекция 6</a>).</p><p>Нотация <emphasis>JSON</emphasis> выглядит очень похоже на простой <emphasis>JavaScript</emphasis>.  <emphasis>JSON</emphasis> означает <emphasis>JavaScript Object Notation</emphasis> и поэтому действительно является обычным <emphasis>JavaScript</emphasis>.</p><p>Данные в любой нотации можно посылать с Web-сервера просто как обычный текст. Никакие пробелы, имеющиеся в этих примерах, не нужны, за исключением одиночных пробелов между именами атрибутов в тегах <emphasis>person</emphasis> (в версии <emphasis>XML</emphasis>).</p><p>Формат <emphasis>XML</emphasis> является совокупностью тегов, очень похожих на <emphasis>HTML</emphasis>.  Можно иметь любое количество тегов, вложенных друг в друга, и каждый тег может иметь любое количество атрибутов: например,  <emphasis>firstname</emphasis>, <emphasis>lastname</emphasis> и <emphasis>phone</emphasis> в примере выше.  Однако имеется несколько вещей, за которыми необходимо следить.</p><p><strong>
		[x].
        </strong> Каждый тег должен иметь закрывающий тег. Например, <emphasis>&lt;contacts&gt;</emphasis> закрывается с помощью расположенного ниже  <emphasis>&lt;/contacts&gt;</emphasis>. Теги <emphasis>person</emphasis> являются замкнутыми. <emphasis>/&gt;</emphasis> в конце действует по сути как дополнительный закрывающий тег. Можно было так же легко написать один из них как <emphasis>&lt;person</emphasis> ... <emphasis>&gt;&lt;/person&gt;</emphasis>.</p><p><strong>
		[x].
        </strong><emphasis>XML</emphasis> имеет ограниченный набор символов, которые можно использовать. В частности следующие символы являются недопустимыми в узлах и атрибутах и должны заменяться специальными комбинациями: 

<p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><td valign="top" bgcolor="#eaeaea">&amp;</td><td valign="top" bgcolor="#eaeaea"> --&gt;</td><td valign="top" bgcolor="#eaeaea">&amp;amp;</td></tr><tr><td valign="top" bgcolor="#eaeaea">&lt;</td><td valign="top" bgcolor="#eaeaea"> --&gt;</td><td valign="top" bgcolor="#eaeaea">&amp;lt;</td></tr><tr><td valign="top" bgcolor="#eaeaea">&gt;</td><td valign="top" bgcolor="#eaeaea"> --&gt;</td><td valign="top" bgcolor="#eaeaea">&amp;gt;</td></tr><tr><td valign="top" bgcolor="#eaeaea">"</td><td valign="top" bgcolor="#eaeaea"> --&gt;</td><td valign="top" bgcolor="#eaeaea">&amp;quot;</td></tr><tr><td valign="top" bgcolor="#eaeaea">'</td><td valign="top" bgcolor="#eaeaea"> --&gt;</td><td valign="top" bgcolor="#eaeaea">&amp;#39;</td></tr></table></p> 

<p>Например, узел <emphasis>&lt;group name="Bill &amp; Paul" /&gt;</emphasis> является недопустимым и должен быть заменен на <emphasis>&lt;group name="Bill &amp;amp; Paul" /&gt;</emphasis>.</p></p><p><strong>
		[x].
        </strong>Приходящие с сервера данные должны посылаться с <emphasis>content-type</emphasis>, заданным как <emphasis>text/xml</emphasis>. Если извлекается файл с расширением <emphasis>.xml</emphasis>, то это должно происходить автоматически. Если данные извлекаются из сценария, необходимо задавать  это вручную.

<p>Для <emphasis>PHP</emphasis> добавьте следующее:</p>


<empty-line/><p id=""></p><p>
&lt;?php header('Content-type: text/xml'); ?&gt;</p><p>
</p><empty-line/>

<p>Для <emphasis>ASP</emphasis> добавьте:</p>


<empty-line/><p id=""></p><p>
&lt;% response.contentType = "text/xml" %&gt;</p><p>
</p><empty-line/>
</p><p><strong>
		[x].
        </strong>Для всех других языков добавьте эквивалентный заголовок <emphasis>content-type</emphasis>. 

<p>Если этот заголовок не задан, свойство <emphasis>responseXML</emphasis> объекта <emphasis>XMLHttp</emphasis> будет пустым (это свойство будет описано далее).</p></p><p><emphasis>JSON</emphasis> имеет аналогичный набор правил, и всю документацию по способам записи можно увидеть на <a l:href="">http://www.json.org/</a>. Однако упрощенно можно сказать, что:</p><p><strong>
		[x].
        </strong>объекты начинаются и заканчиваются с помощью символов  <emphasis>{</emphasis> и  <emphasis>}</emphasis> соответственно;</p><p><strong>
		[x].
        </strong>массивы начинаются и заканчиваются с помощью символов <emphasis>[</emphasis> и <emphasis>]</emphasis> соответственно;</p><p><strong>
		[x].
        </strong>все строки заключаются в двойные кавычки  <emphasis>"</emphasis>;</p><p><strong>
		[x].
        </strong>символы <emphasis>"</emphasis>  в строке должны экранироваться: <emphasis>\"</emphasis>.</p><p>Проще говоря, строка <emphasis>JSON</emphasis> должна представлять допустимый объект <emphasis>JavaScript</emphasis>.</p><p>Теперь посмотрим на то, как можно выполнить синтаксический разбор этих данных. 
В данный момент мы создадим просто сценарий, который сообщит, сколько имеется контактов, и выведет о них информацию. Начнем с версии <emphasis>XML</emphasis>, возвращаясь к предыдущему незаконченному фрагменту кода:</p><empty-line/><p id=""></p><p>
function processingFunction(){</p><p>
  if(oXml.readyState!=4) return; // запрос не выполнен </p><p>
</p><p>
  // Результаты обрабатываются здесь.  Подробнее дальше!</p><p>
}</p><p>
</p><empty-line/><p>Когда скрипт попадает в тело функции, запрос <emphasis>XMLHttp</emphasis> будет выполнен. Объект <emphasis>XMLHttp</emphasis> имеет два метода для возврата данных:  <emphasis>responseXML</emphasis> и <emphasis>responseText</emphasis>.  Так как в данный момент мы работаем с файлом <emphasis>XML</emphasis>, то будем использовать <emphasis>responseXML</emphasis>:</p><empty-line/><p id=""></p><p>
function processingFunction(){</p><p>
  if(oXml.readyState!=4) return;</p><p>
</p><p>
  var xmlDoc   = oXml.responseXML;</p><p>
  var contacts = xmlDoc.selectNodes('/xml/contacts/person');</p><p>
</p><p>
  alert('There are '+contacts.length+' contacts!');</p><p>
</p><p>
  for(var i=0; i&lt;contacts.length; i++){</p><p>
    alert('Contact #'+(i+1)+':\n\n'+</p><p>
        'First Name: '+contacts[i].getAttribute('firstname')+'\n'+</p><p>
        'Last Name:  '+contacts[i].getAttribute('lastname') +'\n'+</p><p>
        'Phone #:    '+contacts[i].getAttribute('phone')    +'\n');</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p>Здесь имеется <emphasis>3</emphasis> функции вывода (<emphasis>alert</emphasis>). Одна сообщает, что имеется два контакта, а еще две выводят контактную информацию для каждого человека.</p><p>Посмотрим на тот же сценарий, использующий текст <emphasis>JSON</emphasis>:</p><empty-line/><p id=""></p><p>
function processingFunction(){</p><p>
  if(oXml.readyState!=4) return;</p><p>
</p><p>
  var json = eval('('+oXml.responseText+')');</p><p>
</p><p>
  alert('There are '+json.contacts.length+' contacts!');</p><p>
</p><p>
  for(var i=0; i&lt;json.contacts.length; i++){</p><p>
    alert('Contact #'+(i+1)+':\n\n'+</p><p>
      'First Name: '+json.contacts[i].firstname+'\n'+</p><p>
      'Last Name:  '+json.contacts[i].lastname +'\n'+</p><p>
      'Phone #:    '+json.contacts[i].phone    +'\n');</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p>Как можно видеть, строки <emphasis>JSON</emphasis> можно преобразовать в <emphasis>JavaScript</emphasis>, используя просто встроенную в <emphasis>JavaScript</emphasis> команду <emphasis>eval()</emphasis>. Однако это можно делать, только если вы полностью доверяете источнику данных. Если это не так (если данные поступают из не вполне известного источника данных), то необходимо пропустить их в целях безопасности через <emphasis>JSON Parser</emphasis> (Анализатор <emphasis>JSON</emphasis>).</p><p>Наконец можно выбрать получение данных в любом другом простом текстовом формате вместо <emphasis>XML</emphasis> или <emphasis>JSON</emphasis>. Однако в этом случае необходимо решить, как выполнить  синтаксический анализ данных. Если имеется только один фрагмент данных, такой, как комментарий, то это может быть практичным решением.</p><p>Что использовать:  <emphasis>XML</emphasis> или <emphasis>JSON</emphasis>? Здесь нет больших различий. <emphasis>XML</emphasis> имеет более широко распространенный формат и переносим почти на любую систему. Если создаваемый проект будет работать с внешними источниками, то, вероятно, лучше использовать <emphasis>XML</emphasis>. Однако <emphasis>JSON</emphasis> немного легче для понимания и в общем он быстрее для разработки кода, чем <emphasis>XML</emphasis>. Если эта технология применяется для персонального проекта или в начале нового проекта, которому не нужно взаимодействовать с другими приложениям, то <emphasis>JSON</emphasis> определенно заслуживает рассмотрения.</p></section><section id="10.section.4"><p>В действительности уже есть все, что нужно для создания приложений <emphasis>AJAX</emphasis>, но мы рассмотрим достаточно простой пример.  Мы собираемся написать небольшую таблицу данных (<emphasis>data grid</emphasis>), которая извлекает данные из трех различных файлов <emphasis>JSON</emphasis>. Для простоты эти файлы уже были сгенерированы. На практике эти файлы будут скорее всего генерироваться оперативно с помощью серверного сценария.</p><p><strong>Файл 1</strong></p><empty-line/><p id=""></p><p>
{contacts:[</p><p>
  {"firstname":"Steve"   ,"lastname":"Smith",   "phone":"555-1212"}, </p><p>
  {"firstname":"Joe"     ,"lastname":"Stevens", "phone":"555-0193"}, </p><p>
  {"firstname":"Sam"     ,"lastname":"Smith",   "phone":"555-5120"}, </p><p>
  {"firstname":"Dave"    ,"lastname":"Stevens", "phone":"555-0521"}, </p><p>
  {"firstname":"Suzy"    ,"lastname":"Smith",   "phone":"555-9410"}, </p><p>
  {"firstname":"Jessica" ,"lastname":"Stevens", "phone":"555-8521"}, </p><p>
  {"firstname":"James"   ,"lastname":"Smith",   "phone":"555-4781"}, </p><p>
  {"firstname":"Jacob"   ,"lastname":"Stevens", "phone":"555-9281"}, </p><p>
  {"firstname":"Alex"    ,"lastname":"Smith",   "phone":"555-7261"}, </p><p>
  {"firstname":"Tam"     ,"lastname":"Stevens", "phone":"555-1820"}</p><p>
]}</p><p>
</p><empty-line/><p><strong>Файл 2</strong></p><empty-line/><p id=""></p><p>
{contacts:[</p><p>
  {"firstname":"Nancy"   ,"lastname":"Smith",   "phone":"555-9583"}, </p><p>
  {"firstname":"Elane"   ,"lastname":"Stevens", "phone":"555-7281"}, </p><p>
  {"firstname":"Shawn"   ,"lastname":"Smith",   "phone":"555-5782"}, </p><p>
  {"firstname":"Jessie"  ,"lastname":"Stevens", "phone":"555-7312"}, </p><p>
  {"firstname":"Matt"    ,"lastname":"Smith",   "phone":"555-4928"}, </p><p>
  {"firstname":"Jason"   ,"lastname":"Stevens", "phone":"555-3917"}, </p><p>
  {"firstname":"Daniel"  ,"lastname":"Smith",   "phone":"555-8711"}, </p><p>
  {"firstname":"Shannon" ,"lastname":"Stevens", "phone":"555-0912"}, </p><p>
  {"firstname":"Diana"   ,"lastname":"Smith",   "phone":"555-6172"},</p><p>
  {"firstname":"Mark"    ,"lastname":"Stevens", "phone":"555-8831"}</p><p>
]}</p><p>
</p><empty-line/><p><strong>Файл 3</strong></p><empty-line/><p id=""></p><p>
{contacts:[</p><p>
  {"firstname":"Laura"     ,"lastname":"Stevens", "phone":"555-3915"}, </p><p>
  {"firstname":"Jeff"      ,"lastname":"Smith",   "phone":"555-8614"}, </p><p>
  {"firstname":"Frank"     ,"lastname":"Stevens", "phone":"555-0213"}, </p><p>
  {"firstname":"Elizabeth" ,"lastname":"Smith",   "phone":"555-7531"}, </p><p>
  {"firstname":"Jim"       ,"lastname":"Stevens", "phone":"555-3951"}</p><p>
]}</p><p>
</p><empty-line/><p>Эти файлы будут обеспечивать все данные для нашего списка контактов на <emphasis>AJAX</emphasis>. Построение списка контактов является в действительности вполне простым: создается таблица <emphasis>TABLE</emphasis> для хранения всех контактов и функция для очищения и повторного заполнения этой таблицы. Вот и все.</p><empty-line/><p id=""></p><p>
&lt;table cellspacing="1" cellpadding="3" bgcolor="#000000" style="font-family:tahoma;font-size:10px;"&gt;</p><p>
  &lt;tbody id="contactListTable"&gt;</p><p>
    &lt;tr style="background-color:#CCF;"&gt;</p><p>
      &lt;th&gt;First Name&lt;/th&gt;</p><p>
      &lt;th&gt;Last Name&lt;/th&gt;</p><p>
      &lt;th&gt;Phone #&lt;/th&gt;</p><p>
    &lt;/tr&gt;</p><p>
  &lt;/tbody&gt;</p><p>
&lt;/table&gt;</p><p>
</p><p>
function loadContactListPage(n){</p><p>
  var oXML = getXMLHttpObj();</p><p>
  oXML.open('GET', '/img/10_json_file'+n+'.txt', true);</p><p>
  oXML.onreadystatechange = function(){ doneLoading(oXML); }</p><p>
  oXML.send('');</p><p>
}</p><p>
</p><p>
function doneLoading(oXML){</p><p>
  if(oXML.readyState!=4) return;</p><p>
</p><p>
  var json  = eval('('+oXML.responseText+')');</p><p>
  var table = document.getElementById('contactListTable');</p><p>
</p><p>
  for(var i=table.childNodes.length-1; i&gt;0; i--){</p><p>
    table.removeChild(table.childNodes[i]);</p><p>
  }</p><p>
</p><p>
  for(var i=0; i&lt;json.contacts.length; i++){</p><p>
    var tr  = document.createElement('TR');</p><p>
    var td1 = document.createElement('TD');</p><p>
    var td2 = document.createElement('TD');</p><p>
    var td3 = document.createElement('TD');</p><p>
</p><p>
    tr.style.backgroundColor = i%2?'#FFF':'#E6E6E6';</p><p>
</p><p>
    table.appendChild(tr);</p><p>
</p><p>
    tr.appendChild(td1);</p><p>
    tr.appendChild(td2);</p><p>
    tr.appendChild(td3);</p><p>
</p><p>
    td1.appendChild(document.createTextNode(json.contacts[i].firstname));</p><p>
    td2.appendChild(document.createTextNode(json.contacts[i].lastname));</p><p>
    td3.appendChild(document.createTextNode(json.contacts[i].phone));</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p><strong>Демонстрационный пример</strong></p><empty-line/><p id=""></p><p>
First Name  Last Name  Phone #</p><p>
</p><p>
Steve    Smith    555-1212</p><p>
Joe    Stevens  555-0193</p><p>
Sam    Smith    555-5120</p><p>
Dave    Stevens  555-0521</p><p>
Suzy    Smith    555-9410</p><p>
Jessica    Stevens  555-8521</p><p>
James    Smith    555-4781</p><p>
Jacob    Stevens  555-9281</p><p>
Alex    Smith    555-7261</p><p>
Tam    Stevens  555-1820</p><p>
</p><p>
Page 1 | Page 2 | Page 3 </p><p>
</p><empty-line/><p>Как можно видеть из примера выше, это все достаточно просто.  Большая часть кода 
нужна в действительности просто для создания новых строк в таблице.</p><p><emphasis>AJAX</emphasis> может быть удивительно полезным инструментом. Его можно использовать для проверки форм перед их отправкой, для извлечения данных, как в этом примере, или для чего-то еще, что  можно будет придумать.  Однако в нормальной ситуации он не должен быть основным элементом Web-сайта. Обычно надо быть уверенным, что сайт будет доступен, даже если <emphasis>JavaScript</emphasis> будет отключен, но всегда существуют некоторые исключения для этого правила.</p><p><a l:href="">Следующая лекция</a>  будет посвящена обработке ошибок в <emphasis>JavaScript</emphasis>.</p></section></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="11.lecture"><title><p>Лекция 11.
 Обработка ошибок в JavaScript</p></title><annotation>Обработка ошибок в JavaScript: Синтаксические ошибки. Ошибки времени выполнения. Window.onerror. Try/Catch/Finally и Throw. Обработка ошибок в AJAX</annotation><section id="11.section.1"><p>Вы написали приложение <emphasis>JavaScript</emphasis>, и оно работает отлично - пока вы не получите сообщение об ошибке. Это нечто неприглядное, выскакивающее на экране, что-нибудь вроде <emphasis>'myObject.fields is null or not an object'</emphasis>. Что это значит? В этом уроке мы рассмотрим, как избавиться от ошибок, и покажем несколько различных методов для общей обработки ошибок.</p><section id="11.section.2"><p><emphasis>JavaScript</emphasis> имеет два основных уровня обработки ошибок: синтаксические ошибки и ошибки времени выполнения. Синтаксические ошибки возникают до выполнения кода JavaScript, означая в основном, что код невозможно компилировать. Возьмем, например, следующий код:</p><empty-line/><p id=""></p><p>
for(var i=0; i&lt;10; i++)</p><p>
  // рабочий код здесь </p><p>
}</p><p>
</p><empty-line/><p>Обратите внимание, что здесь пропущена  открывающая скобка <emphasis>{</emphasis>. Если попробовать выполнить этот код, то немедленно появится сообщение об ошибке, даже если код находится в функции, которая не выполняется сразу. Такие ошибки почти всегда легко находятся и исправляются. В этом случае будет получено сообщение, говорящее что-нибудь подобное " <emphasis>Ожидалась ')', строка 10, позиция 18</emphasis>".  Если перейти к строке <emphasis>10</emphasis>, то там обычно будет находиться достаточно очевидная ошибка, такая, как пропущенная <emphasis>)</emphasis>, дополнительный знак <emphasis>&lt;</emphasis>или какая-то другая опечатка. С такими ошибками ничего нельзя сделать, кроме как просто исправить и двигаться дальше.  Ниже представлен список некоторых наиболее распространенных синтаксических ошибок:</p><p><strong>
		[x].
        </strong> Пропущенные или непарные фигурные, круглые или квадратные скобки

<p>Каждая фигурная <emphasis>{</emphasis>, круглая <emphasis>(</emphasis>, или квадратная <emphasis>[</emphasis> скобка должна иметь свою закрывающую парную скобку. Если имеются вложенные скобки, то внутренние должны быть закрыты прежде, чем внешние. Например, набор скобок <emphasis>{[}]</emphasis> является недопустимым.</p>

<p>Условия операторов <emphasis>if</emphasis>, <emphasis>for</emphasis> и <emphasis>while</emphasis> должны помещаться в круглые скобки. Выражнение "<emphasis>if x=5{</emphasis>" является недопустимым, так как "<emphasis>x=5</emphasis>" должно быть заключено в круглые скобки. Если с этим возникнут проблемы, то существуют редакторы, такие, как <emphasis> EditPlus</emphasis>, которые могут выделять соответствующие пары скобок, и т.д.</p></p><p><strong>
		[x].
        </strong> Пропущенные или непарные кавычки 

<p>Это очень распространенная проблема. Строки в <emphasis>JavaScript</emphasis> начинаются символом <emphasis>'</emphasis>или  <emphasis>"</emphasis> и должны заканчиваться таким же символом. Если этот символ существует в строке, то он должен быть экранирован. Например, код</p>

<empty-line/><p id=""></p><p>
var x = 'It's a beautiful day';</p><p>
</p><empty-line/>

<p>является недопустимым, потому что <emphasis>'</emphasis> в <emphasis>It's</emphasis> не экранировано. Этот код должен выглядеть следующим образом:</p>

<empty-line/><p id=""></p><p>
var x = 'It\'s a beautiful day';</p><p>
</p><p>
// или</p><p>
</p><p>
var x = "It's a beautiful day";</p><p>
</p><empty-line/>

<p>Еще одной достаточно распространенной ошибкой является завершение строки другим символом, т.е.:</p>

<empty-line/><p id=""></p><p>
var x = "It's a beautiful day';</p><p>
</p><empty-line/>

<p>Эта строка начинается с символа <emphasis>"</emphasis>, поэтому должна закончиться также символом <emphasis>"</emphasis>.</p></p><p><strong>
		[x].
        </strong> Пропущенная точка с запятой 

<p>Хотя точки с запятой обычно не нужны в <emphasis>JavaScript</emphasis>, но лучше все же их использовать. 
Например, если нужно сократить файл <emphasis>JavaScript</emphasis>, то обычно удаляют все переносы строк. Возьмем следующий код:</p>

<empty-line/><p id=""></p><p>
var x=5</p><p>
var y=10</p><p>
</p><empty-line/>

<p>Если удалить переносы строк, то получим код</p>
<empty-line/><p id=""></p><p>
var x=5 var y=10</p><p>
</p><empty-line/>

<p>который вызовет ошибку. Если бы использовались точки с запятой, то проблемы не было бы.</p></p></section><section id="11.section.3"><p>Перейдем к ошибкам времени выполнения. После запуска кода на исполнение начинают появляться ошибки времени выполнения. Эти ошибки могут возникать в связи с множеством причин. Каждый из следующих далее блоков кода будет порождать ошибку:</p><empty-line/><p id=""></p><p>
alert(x); // 'x' не определено </p><p>
</p><p>
var x;</p><p>
</p><p>
x[5] = 'test'; // 'x' будет null или не является объектом </p><p>
</p><p>
</p><p>
window.frames = 5; //  Не реализовано </p><p>
</p><p>
</p><p>
var for; // ожидается идентификатор </p><p>
</p><p>
document.doesNotExist(5);</p><p>
// объект не поддерживает это свойство или метод </p><p>
</p><p>
</p><p>
alert(parseInt('5')); // ожидается объект </p><p>
</p><empty-line/><p>Многие  из этих проблем вызываются более общими ошибками, которые приходится разыскивать.</p><p><strong>
		[x].
        </strong> Неправильное использование прописных букв 

<p>Все встроенные функции <emphasis>JavaScript</emphasis> используют специальную форму записи имен функций, предполагающую, что имя функции начинается со строчной буквы, а в начале каждого следующего слова будет использоваться прописная буква: <emphasis>parseInt</emphasis>, getElementById, <emphasis>createElement</emphasis>, <emphasis>appendChild</emphasis>, и т.д.</p>

<p>Так как <emphasis>JavaScript</emphasis> учитывает регистр символов, то неправильный ввод имени одной из этих функций часто будет приводить к ошибке во время выполнения.</p></p><p><strong>
		[x].
        </strong> Ссылка на несуществующий код, функции или объекты <emphasis>DOM</emphasis> 

<p>Эта проблема возникает обычно в отношении объектов <emphasis>DOM</emphasis>. Предположим, что имеется код, который изменяет некоторые элементы формы на странице. Если делается попытка выполнить этот код до появления элементов формы, например, если поместить его в тег <emphasis>&lt;HEAD&gt;</emphasis>, то будет получена  ошибка <emphasis>JavaScript</emphasis>.</p>

<p>Обычно эта проблема легко решается. Лучшим решением будет выполнение кода по событию <emphasis>onload</emphasis>, например:</p>

<empty-line/><p id=""></p><p>
&lt;BODY onload="loadFunction();"&gt;</p><p>
</p><empty-line/>

<p>или еще лучше, присоединение события к загрузке тела:
<empty-line/><p id=""></p><p>
document.captureEvents(Event.LOAD);</p><p>
document.onLoad=loadFunction;</p><p>
</p><empty-line/></p></p><p><strong>
		[x].
        </strong> Использование зарезервированного слова 

<p>Существует длинный список зарезервированных ключевых слов <emphasis>JavaScript</emphasis>. Если делается попытка использовать многие из них вне их специального контекста, как,  например, запись</p>

<empty-line/><p id=""></p><p>
var for = 5;</p><p>
</p><empty-line/>

<p>то будет возникать ошибка.</p></p><p><strong>
		[x].
        </strong> Использование пропущенного параметра 

<p>При определении функции обычно используется некоторое количество аргументов. Если некоторые из этих аргументов пропущены и делается попытка их использовать, то возникнут ошибки.</p></p><p>Большинство из этих проблем попадают в категорию опечаток и просто обычных ошибок, которые можно исправить, но необходимо о них знать, чтобы случайно не сделать.</p><p>Однако последний тип ошибки из этого списка с пропущенными параметрами можно проверить достаточно легко:</p><empty-line/><p id=""></p><p>
function myFunction(a, b, c){</p><p>
  if(a){</p><p>
    // выполняется работа с a</p><p>
  }</p><p>
  if(b &amp;&amp; c){</p><p>
    // выполняется работа с b и c</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p>Если функция вызывается  только с одной переменной, то проблемы не возникает. Однако надо помнить об одной вещи: если входящая по значению переменная может быть определена как <emphasis>false</emphasis> <emphasis>(0</emphasis> или <emphasis>false</emphasis>), то код не будет работать. В связи с этим  лучше проверять, что переменная не была определена:</p><empty-line/><p id=""></p><p>
function myFunction(a, b, c){</p><p>
  if(typeof(a)!='undefined'){</p><p>
    // выполнение кода с a</p><p>
  }</p><p>
  if((typeof(b)!='undefined') &amp;&amp; (typeof(c)!='undefined')){</p><p>
    // выполнение кода с b и c</p><p>
  }</p><p>
}</p><p>
</p><empty-line/><p>В этом случае, даже если одна из переменных будет передана как <emphasis>0</emphasis>, <emphasis>false</emphasis>  или <emphasis>null</emphasis>, код все равно будет работать.</p><p>Сейчас мы перейдем к изучению механизмов обработок ошибок - с помощью операторов Try/Catch и функции window.onerror.</p></section><section id="11.section.4"><p>Откровенно говоря, функция <emphasis>window.onerror</emphasis>  имеет небольшую практическую пользу. Ее чаще всего используют для полного отключения всех сообщений об ошибках во время выполнения:</p><empty-line/><p id=""></p><p>
window.onerror = function(){</p><p>
  return true;</p><p>
}</p><p>
</p><empty-line/><p>С этим кодом сообщение об ошибке никогда не будет выводиться. Однако в связи с этим приложение может не работать. Например, если бы переменная была <emphasis>null</emphasis> и с ней была выполнена какая-то операция, то в обычной ситуации должно появиться сообщение об ошибке.  При использовании этого кода функция или сценарий в случае возникновения ошибки будет просто молча останавливаться.</p><p>Функцию <emphasis>window.onerror</emphasis> можно также использовать для вывода пользователям несколько более дружественных сообщений об ошибках. Можно просто вывести, например, сообщение <emphasis>'Произошла ошибка, свяжитесь, пожалуйста, с Web-мастером'</emphasis>, вместо вывода пользователю всех технических деталей ошибки (что большинство браузеров делает по умолчанию).</p><p>Еще одно использование <emphasis>window.onerror</emphasis> состоит в отправке разработчику списка всех ошибок, произошедших на сайте. Можно использовать <emphasis>AJAX</emphasis> для отправки сообщений об ошибках в форме, чтобы можно было позже их исправить. Все это возможно  сделать неявно, без взаимодействия с пользователем.</p></section><section id="11.section.5"><p>Операторы <emphasis>Try/Catch</emphasis> являются несомненно наиболее распространенным и обычно лучшим способом реализовать обработку ошибок в <emphasis>JavaScript</emphasis>. Но не только это - операторы <emphasis>Try/Catch</emphasis> могут иногда быть единственным способом реализовать некоторые задачи, такие, как обнаружение объекта. Возьмем, например, простую функцию для создания в <emphasis>Internet Explorer</emphasis> объекта <emphasis>XMLHttp</emphasis>:</p><empty-line/><p id=""></p><p>
var activeXObjects = ['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0',</p><p>
'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];</p><p>
for(var i=0; i&lt;activeXObjects.length; i++){</p><p>
  try{</p><p>
    return new ActiveXObject(activeXObjects[i]);</p><p>
  }catch(err){}</p><p>
}</p><p>
</p><empty-line/><p>Заранее неизвестно, какие объекты установил пользователь, и, к сожалению, браузер не предоставляет никакого механизма это определить. Поэтому остается создавать каждый из 6 возможных объектов, пока один из них (будем надеяться) не заработает.</p><p>Операторы <emphasis>Try/Catch</emphasis> можно использовать для перехвата ошибок двух типов: ошибок времени выполнения и ошибок пользователя. Ошибки времени выполнения, как говорилось ранее, возникают, когда у компилятора <emphasis>JavaScript</emphasis> существует проблема с созданным кодом. Ошибки пользователя, с другой стороны, будут технически проходить без проблем, но возникают в связи с контекстом приложения. Если имеется поле, в которое пользователь, например, должен ввести свой возраст, и пользователь вводит <emphasis>-2</emphasis>, то это приводит к появлению ошибки.</p><p>Блок <emphasis>Try/Catch</emphasis> имеет достаточно простой синтаксис:</p><empty-line/><p id=""></p><p>
try{</p><p>
  // код </p><p>
}catch(err){</p><p>
  // код обработки ошибки </p><p>
}</p><p>
</p><empty-line/><p>Если код в блоке <emphasis>try</emphasis> приводит к ошибке, то сценарий немедленно переходит в блок <emphasis>catch</emphasis>. Объект ошибки <emphasis>err</emphasis> в <emphasis>JavaScript</emphasis> имеет ряд полезных свойств - описание, сообщение, имя и номер, которые можно использовать для вывода информации о том, что произошло:</p><empty-line/><p id=""></p><p>
try{</p><p>
  var x;</p><p>
  x[5] = 5;</p><p>
}catch(err){</p><p>
  alert('An error occured: '+err.description);</p><p>
}</p><p>
</p><empty-line/><p>Если в операторе <emphasis>catch</emphasis> окажется ошибка, то <emphasis>JavaScript</emphasis> сможет обратиться в дальнейшем к ее описанию.</p><p>Такой блок кода <emphasis>Try/Catch</emphasis> можно применять в любом месте. Однако, обычно, код должен быть написан таким образом, чтобы это не нужно было использовать, - в  частности, весь ввод должен проверяться.</p><p>Блок <emphasis>Try/Catch</emphasis> можно применять также для создания своих собственных ошибок:</p><empty-line/><p id=""></p><p>
function setAge(x){</p><p>
  if(typeof(x)=='undefined') throw('Вы должны ввести возраст');</p><p>
  if(typeof(x)!='number') throw('Возраст должен быть числом');</p><p>
  if(x&lt;0) throw('Возраст не может быть меньше 0');</p><p>
  if(x&gt;120) throw('Возраст не может быть больше 120');</p><p>
</p><p>
  var myAge = x;</p><p>
</p><p>
  // еще код </p><p>
}</p><p>
</p><p>
try{</p><p>
  setAge(userInput);</p><p>
}catch(err){</p><p>
  alert(err);</p><p>
}</p><p>
</p><empty-line/><p>В этом случае выполняется проверка того, что пользователь вводит возраст. Если он вводит недопустимые данные, сценарий немедленно завершается, а пользователь получает сообщение об ошибке.</p><p>Блок <emphasis>try/catch</emphasis> имеет еще одну часть, оператор <emphasis>finally</emphasis>:</p><empty-line/><p id=""></p><p>
try{</p><p>
  // код </p><p>
}catch(err){</p><p>
  // код </p><p>
}finally{</p><p>
  // код </p><p>
}</p><p>
</p><empty-line/><p>Код в "завершающем блоке" будет выполняться независимо от того, что происходит с операторами  <emphasis>Try/Catch</emphasis>. В чем же разница между завершающим блоком и простым размещением кода после блока <emphasis>try/catch</emphasis>?  В большинстве случаев никакой разницы не будет. Однако, если блок <emphasis>try/catch</emphasis> находится в функции и происходит выход из функции в блоке <emphasis>try</emphasis> или <emphasis>catch</emphasis>, то возникнет существенное различие:</p><empty-line/><p id=""></p><p>
function myFunction(){</p><p>
  try{</p><p>
    return someValue;</p><p>
  }catch(err){</p><p>
    return defaultValue;</p><p>
  }finally{</p><p>
    alert('finally!');</p><p>
  }</p><p>
</p><p>
  alert('End!');</p><p>
}</p><p>
</p><empty-line/><p>В этом случае оба блока <emphasis>try</emphasis> и <emphasis>catch</emphasis> возвращают значение. Мы получим сообщение "<emphasis>finally!</emphasis>", но не получим сообщение "<emphasis>End!</emphasis>", потому что произойдет выход из функции до сообщения <emphasis>alert('End!')</emphasis>. То же самое остается справедливым для операторов <emphasis>Try/Catch</emphasis>, которые осуществляют выход из тела цикла <emphasis>for</emphasis> или <emphasis>while</emphasis>, например:</p><empty-line/><p id=""></p><p>
for(var i=0; i&lt;10; i++){</p><p>
  try{</p><p>
    if(i==5) continue;</p><p>
  }catch(err){</p><p>
    // обработка ошибки </p><p>
  }finally{</p><p>
    // код </p><p>
  }</p><p>
</p><p>
  // еще код </p><p>
}</p><p>
</p><empty-line/></section></section><section id="11.section.6"><p>Запросы <emphasis>XMLHttp</emphasis>, рассмотренные в <a l:href="">предыдущей лекции</a>, могут иметь совершенно другой тип ошибки: данные просто не проходят. Это можно проверить через статус объекта <emphasis>XMLHttp</emphasis>:</p><empty-line/><p id=""></p><p>
function processingFunction(){</p><p>
  if(oXml.readyState!=4) return; // запрос не выполнен </p><p>
</p><p>
  switch(oXml.status){</p><p>
    case 0: case 200:  // запрос выполнен </p><p>
      break;</p><p>
    case 408: case 504: // запрос превысил время ожидания </p><p>
      // код </p><p>
      break;</p><p>
    default: // ошибка запроса </p><p>
      // код</p><p>
      return; // возможно, вы захотите выйти </p><p>
      break;</p><p>
  }</p><p>
</p><p>
  // продолжение обработки запроса </p><p>
}</p><p>
</p><empty-line/><p><emphasis>oXml</emphasis> в этом примере является объектом <emphasis>XMLHttp</emphasis>, а функция <emphasis>processingFunction</emphasis> была присоединена к свойству <emphasis>onreadystatechange</emphasis> этого объекта.</p><p>Проверяя код статуса, мы узнаем, был ли запрос обработан успешно. Код <emphasis>200</emphasis>  является в HTTP стандартным кодом статуса "Все прошло нормально" .  Код <emphasis>0</emphasis> возникает при загрузке файлов из локальной файловой системы (если для этого есть соответствующие полномочия). Статус код <emphasis>0</emphasis> часто возникает при локальном тестировании приложения.</p><p>Коды статуса <emphasis>408</emphasis> и <emphasis>504</emphasis> представляют ситуацию с превышением времени ожидания. Очень часто это указывает на сетевые проблемы, и простое повторение запроса  может разрешить проблему. Однако отметим, что эти коды представляют также слишком  длительную работу сервера над ответом.  Например, если существует ошибка сценария на сервере, которая приводит к бесконечному циклу, то может возникнуть код ошибки <emphasis>408</emphasis> или <emphasis>504</emphasis>. В этом случае повторная попытка будет вредоносной, поэтому надо быть осторожным.  Самым безопасным является уведомление пользователя и выход из функции, но это не очень корректно по отношению  к пользователю.</p><p>Все другие коды ошибок имеют свои собственные значения, но в данной ситуации это не важно. Нас интересует только то, что мы не получили нужные данные. Поэтому если код попадает в область "<emphasis>default</emphasis>", то мы имеем проблему. Наверно в этой ситуации лучше всего сообщить пользователю о проблеме и выйти из функции.</p><p>Это почти все об обработке ошибок в <emphasis>JavaScript</emphasis>. Имеет смысл включать в функции обработку ошибок, но, возможно, что это не требуется для каждой функции или каждого фрагмента кода. В большинстве ситуаций достаточно проверки ввода пользователей.  Для реализации проверки пользователя наиболее полезным средством является использование блоков <emphasis>Try/Catch/Throw</emphasis>.</p><p>В <a l:href="">следующей лекции</a> будет рассмотрена рекурсия:</p><cite>"Чтобы понять рекурсию, сначала необходимо понять рекурсию".</cite></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="12.lecture"><title><p>Лекция 12.
 Рекурсия</p></title><annotation>Рекурсия. Стек. Создание собственного стека. Применение рекурсии.</annotation><section id="12.section.1"><cite>"Чтобы понять рекурсию, сначала необходимо понять рекурсию".</cite><p>Данное высказывание очень четко выражает суть рекурсии. Рекурсия является базовой концепцией программирования вообще, а не только <emphasis>JavaScript</emphasis>, понимание которой очень полезно. Она включает вызов функции из той же самой функции.  Почему это может понадобиться? Предположим, что имеется массив массивов. Каждый из этих массивов может иметь в себе массивы, которые могут иметь массивы, которые могут иметь ... собственно, в этом и состоит идея. Таким образом мы имеем множество массивов в других массивах. Как выполнить одну и ту же операцию на всех элементах во всех этих массивах? Можно попробовать использовать простой цикл <emphasis>for</emphasis>, но неизвестно, сколько имеется массивов, и неизвестно, как глубоко распространяется вложение массивов. Поэтому остается только концепция рекурсии.</p><p>В этом примере мы циклически перебираем все элементы массива первого уровня. Если какой-либо из этих элементов в массиве сам будет массивом, мы снова вызываем функцию, передавая этот элемент как первичный массив. Затем функция будет перебирать этот массив и снова вызывать себя, пока не останется ни одного массива.    
</p><p>Другим хорошим примером рекурсии будет написание синтаксического анализатора документа <emphasis>XML</emphasis>. Каждый узел документа <emphasis>XML</emphasis> можно анализировать совершенно одинаково, поэтому мы можем разбить всю задачу на множество более мелких одинаковых шагов.</p><p>Самым трудным в рекурсии является ее понимание. Такие концепции, как циклы, воспринимаются достаточно естественно, в то время как рекурсия трудна для большинства людей. Рекурсивные функции также очень часто требуют больше памяти, чем нерекурсивные функции. Если имеется функция, которая вызывает себя на <emphasis>20</emphasis> уровней вглубь, потребуется как минимум в <emphasis>20</emphasis> раз больше памяти.</p><p>Простым примером будет написание рекурсивной функции факториала. Факториал <emphasis>N</emphasis>, записываемый как <emphasis>N!</emphasis>, определяется как произведение всех чисел от <emphasis>N</emphasis> до <emphasis>1</emphasis>. Поэтому <emphasis>5!</emphasis> будет равен <emphasis>5*4*3*2*1 = 120</emphasis>.</p><empty-line/><p id=""></p><p>
function factorial(N){</p><p>
	return N&lt;=1?1:N*factorial(N-1);</p><p>
}</p><p>
</p><p>
</p><empty-line/><p>Демонстрационный пример</p><empty-line/><p id=""></p><p>
Факториал </p><p>
</p><empty-line/><p>Очень элегантное решение, не правда ли? В результате мы вызываем функцию факториала <emphasis>5</emphasis> раз для <emphasis>N = 5</emphasis>. Можно в действительности развернуть всю рекурсивную функцию и получить <emphasis>(5*(4*(3*(2*(1)))))</emphasis>. Каждая пара скобок представляет новый вызов функции факториала. Можно также видеть, что если пользователь вводит число <emphasis>&lt;=1</emphasis>, то всегда получит в качестве результата <emphasis>1</emphasis>.</p><p>Давайте рассмотрим другой пример. При работе с программами рисования, такими, как <emphasis>Photoshop</emphasis> или <emphasis>MS Paint</emphasis>, иногда используется инструмент заливки (<emphasis>flood fill</emphasis>). Этот инструмент заливает выбранный цвет другим, указанным цветом. Это делается рекурсивно, и алгоритм заливки достаточно прямолинеен:</p><empty-line/><p id=""></p><p>
/*</p><p>
это - псевдо-код, быстро написанный и нефункциональный, </p><p>
который должен просто дать общую идею о том, как действует </p><p>
реальный код</p><p>
*/</p><p>
</p><p>
function floodFill(x, y){</p><p>
	if(alreadyFilled(x, y)) return;</p><p>
	fill(x, y);</p><p>
</p><p>
	floodFill(x,   y-1);</p><p>
	floodFill(x+1, y  );</p><p>
	floodFill(x,   y+1);</p><p>
	floodFill(x-1, y  );</p><p>
}</p><p>
</p><p>
function fill(x, y){</p><p>
	// эта функция будет фактически изменять цвет поля </p><p>
}</p><p>
</p><p>
function alreadyFilled(x, y){</p><p>
	// эта функция проверяет, что поле уже было закрашено </p><p>
}</p><p>
</p><empty-line/><p>Идея этого кода состоит в том, чтобы закрасить текущий квадрат или пиксель. Затем он пытается закрасить квадрат выше, справа, ниже и слева от себя. При таком алгоритме каждый квадрат будет закрашен достаточно быстро. Однако здесь возникает небольшая проблема - размер стека.</p></section><section id="12.section.2"><p>При вызове функции копия множества переменных, которые нужны ей для работы, сохраняется в памяти. Если функция вызывается рекурсивно, то другая копия всех этих переменных сохраняется в памяти, затем еще одна и т.д. Эти копии переменных сохраняются в так называемом стеке. Первая копия находится внизу, следующая поверх нее, и т.д.  К сожалению, существует ограничение на размер стека. В большинстве браузеров этот предел определен где-то в районе <emphasis>1000</emphasis>. Это означает, что для функции заливки сетка могла бы содержать до <emphasis>1000</emphasis> квадратов. Некоторые браузеры имееют меньший размер стека. Web-браузер <emphasis>Safari</emphasis>, например, имеет максимальный размер стека, равный примерно <emphasis>100</emphasis>, поэтому даже небольшая сетка <emphasis>10 х 10</emphasis> исчерпает возможности браузера.</p><p>Таким образом мы имеем ограничение в самом браузере, которое определяет, что при использовании рекурсии можно углубиться только на <emphasis>1000</emphasis> уровней. К сожалению, наш алгоритм  <emphasis>floodFill</emphasis> (заливки) будет в худшем случае углубляться на <emphasis>1000</emphasis> уровней на сетке, содержащей только <emphasis>1000</emphasis> полей. Если имеется что-то более сложное, то существует вероятность, что произойдет переполнение стека и просто остановка выполнения кода. Очевидно, что существуют ситуации, когда необходимо закрасить область, содержащую  более <emphasis>1000</emphasis> пикселей. Что делать в таком случае? Попробуем изменить подход.</p><p>Прежде всего попробуем изменить алгоритм. Существует много различных алгоритмов закраски - мы использовали один из самых простых. Он проверяет все направления и затем закрашивает каждый просмотренный квадрат, если это будет необходимо.  С помощью небольшого изменения можно существенно улучшить этот алгоритм, с  точки зрения необходимого пространства стека.  Вместо просмотра влево и вправо на <emphasis>1</emphasis> квадрат, можно просматривать влево и вправо на максимально возможное количество позиций и закрашивать каждый пиксель в этом направлении. Это называется алгоритмом закрашивания со сканированием по линиям, который оказывается одним из наиболее эффективных существующих алгоритмов закрашивания. К сожалению, он все еще имеет свои ограничения, и для достаточно большой области закрашивания он также может переполнять стек.</p><p>Если это произойдет, то остается единственный вариант: не использовать рекурсию. Вместо использования стека <emphasis>JavaScript</emphasis> можно создать свой собственный с помощью простого массива <emphasis>JavaScript</emphasis>. Так как массив не имеет ограничений на количество элементов массива, то можно получить "бесконечно" большой стек, которым мы  управляем самостоятельно.</p></section><section id="12.section.3"><p>Чтобы создать свой собственный стек, необходимо удалить рекурсивную часть нашей функции. Мы все равно собираемся многократно вызывать функцию, но собираемся вызывать ее из другой функции, а не из себя самой.</p><empty-line/><p id=""></p><p>
var Stack = [];</p><p>
</p><p>
function floodFill(x, y){</p><p>
	fillPixel(x, y);</p><p>
</p><p>
	while(Stack.length&gt;0){</p><p>
		toFill = Stack.pop();</p><p>
		fillPixel(toFill[0], toFill[1]);</p><p>
	}</p><p>
}</p><p>
</p><p>
function fillPixel(x, y){</p><p>
	if(!alreadyFilled(x, y)) fill(x, y);</p><p>
</p><p>
	if(!alreadyFilled(x,   y-1)) Stack.push([x,   y-1]);</p><p>
	if(!alreadyFilled(x+1, y  )) Stack.push([x+1, y  ]);</p><p>
	if(!alreadyFilled(x,   y+1)) Stack.push([x,   y+1]);</p><p>
	if(!alreadyFilled(x-1, y  )) Stack.push([x-1, y  ]);</p><p>
}</p><p>
</p><p>
function fill(x, y){</p><p>
	// эта функция будет фактически изменять цвет поля </p><p>
}</p><p>
</p><p>
function alreadyFilled(x, y){</p><p>
	// эта функция проверяет, что квадрат еще не был закрашен </p><p>
}</p><p>
</p><p>
</p><empty-line/><p>Как можно видеть, процесс не намного сложнее, но требует немного больше микроуправления, чем написанный ранее рекурсивный код. Вместо рекурсивного вызова функции <emphasis>floodFill</emphasis> создается переменная <emphasis>Stack</emphasis>, содержащая список квадратов, которые необходимо закрасить. Затем функция <emphasis>fillPixel</emphasis> заполняет этот массив, а функция <emphasis>floodFill</emphasis> извлекает последний элемент и закрашивает его. Когда все будет сделано, результат будет таким же, как и у первой функции, которая была написана, с одним исключением: эта функция не имеет никаких ограничений в отношении величины сетки.</p><p>Отметим, что существует очень немного рекурсивных функций, которые будут реально переполнять стек <emphasis>JavaScript</emphasis>. В действительности это не совсем верно. Почти любая рекурсивная функция может переполнить стек, но чаще всего данные, которые  функция получает от пользователя, делают это крайне маловероятным событием.   Когда, например, вы встретите документ <emphasis>XML</emphasis> с глубиной вложения узлов, равной <emphasis>1000</emphasis>? Почти наверняка - никогда.</p></section><section id="12.section.4"><p>Теперь, имея некоторое представление о рекурсии, надо попытаться понять, что с ней можно делать, кроме закрашивания изображений. Одним из наиболее распространенных рекурсивных алгоритмов будет так называемый двоичный поиск.  Это можно представить себе как игру на больше-меньше. Если кто-то предлагает угадать число от <emphasis>1</emphasis> до <emphasis>100</emphasis>, то, скорее всего, начать лучше с  <emphasis>50</emphasis>. Если партнер скажет, что больше, то можно предположить  <emphasis>75</emphasis> и т.д. Это можно продолжать, пока число не будет найдено.</p><p>Как оказывается, это один из самых быстрых способов поиска данных, когда известно, что все данные уже отсортированы. Если имеется список из <emphasis>1000000</emphasis> позиций и требуется найти одну из них, то можно начать с <emphasis>500000</emphasis> и использовать тот же процесс, что и в игре "больше-меньше".</p><p>Для сортировки применяются специальные алгоритмы. Многие алгоритмы сортировки, включая один из самых быстрых, <emphasis>QuickSort</emphasis>, используют рекурсию. Алгоритм <emphasis>QuickSort</emphasis> разбивает данные на фрагменты,  сортирует каждый фрагмент по отдельности, рекурсивно разбивает фрагменты на меньшие фрагменты и сортирует их.</p><p>Другим широко распространенным использованием рекурсии является проверка или синтаксический анализ некоторых данных. Ранее в качестве примера упоминался файл <emphasis>XML</emphasis>, но с помощью рекурсии можно эффективно выполнять многие другие формы синтаксического анализа, такие, как подсчет количества вхождений слова или фразы в предложении или книге.</p><p>Рекурсия является крайне полезной концепцией. Рекурсия может использоваться не так часто, но когда она находит применение, она существенно облегчает жизнь программиста.</p></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="lectures_adds"><title><p>Дополнения</p></title><section id="13.lecture"><title><p>Дополнение.
 Краткое руководство по AJAX</p></title><annotation/><section id="13.section.1"><p> Технология AJAX является не новым языком программирования, а просто новым способом использования существующих стандартов.</p><p>С помощью AJAX можно создавать Web-приложения, которые будут лучше, быстрее и удобнее для пользователей, чем существующие.</p><p>AJAX основывается на JavaScript и запросах HTTP.</p><section id="13.section.2"><p>AJAX является сокращением от "Asynchronous JavaScript And XML" (Асинхронный JavaScript и XML).</p><p>AJAX является не новым языком программирования, а просто новым способом создания Web-приложений, которые будут лучше, быстрее, и более интерактивными.</p><p>AJAX использует JavaScript для отправки и получения данных при взаимодействии Web-браузера и Web-сервера.</p><p>Технология AJAX делает Web-страницы более гибкими и быстро реагирующими, осуществляя обмен данными с Web-сервером в фоновом режиме, а не перезагружая всю Web-страницу всякий раз, когда пользователь делает изменение. </p></section><section id="13.section.3"><p>AJAX является технологией, которая выполняется в браузере клиента. Она использует асинхронную передачу данных (запросы HTTP) между браузером и Web-сервером, позволяя Web-страницам запрашивать с сервера небольшие объемы данных вместо целых страниц. </p><p>Эта технология позволяет уменьшить объем приложений Интернет, сделать их более быстрыми и более удобными для пользователей. </p><p>AJAX является технологией Web-браузера, которая не зависит от программного обеспечения Web-сервера. </p></section><section id="13.section.4"><p>AJAX использует следующие открытые стандарты:</p><p><strong>JavaScript</strong></p><p><strong>XML</strong></p><p><strong>HTML</strong></p><p><strong>CSS</strong></p><p>Используемые в AJAX открытые стандарты строго определены и поддерживаются всеми основными браузерами. Приложения AJAX не зависят от используемых браузеров и платформ. </p></section><section id="13.section.5"><p>Web-приложения имеют множество преимуществ при сравнении с традиционными приложениями настольных компьютеров. Они имеют более обширную аудиторию, их легче устанавливать и поддерживать, и их легче разрабатывать.</p><p>Однако приложения Интернет не всегда бывают достаточно "богаты" свойствами и удобны для использования по сравнению с традиционными приложениями. </p><p>С помощью AJAX приложения Интернет можно сделать богаче (меньше, быстрее, и легче в использовании).</p></section><section id="13.section.6"><p>Нет ничего нового, что требует изучения.</p><p>Технология AJAX основывается на открытых стандартах. Эти стандарты использовались множеством разработчиков многие годы.</p><p>Большинство существующих Web-приложений можно легко переписать с помощью технологии AJAX вместо традиционных форм HTML.</p></section><section id="13.section.7"><p>Традиционное Web-приложение посылает введенные данные на Web-сервер (используя форму HTML). После обработки данных Web-сервер возвращает пользователю совершенно новую Web-страницу.</p><p>Так как сервер возвращает новую Web-страницу всякий раз, когда пользователь посылает данные на сервер, то традиционное Web-приложение часто выполняется медленно и оказывается менее удобным для  пользователя.</p><p>С помощью AJAX Web-приложения могут посылать и получать данные без перезагрузки всей Web-страницы. Это делается с помощью запросов HTTP, посылаемых на сервер (в фоновом режиме), и модификации только отдельных частей Web-страницы с помощью JavaScript, когда сервер возвращает данные.    </p><p>XML используется обычно в качестве формата для получения данных сервера, хотя можно использовать любой формат, включая обычный текст. </p><p>Как это делается, будет показано далее в этом кратком руководстве.</p></section></section><section id="13.section.8"><p>Технологию AJAX можно использовать для создания приложений с большими интерактивными возможностями. </p><section id="13.section.9"><p>В следующем примере приложения AJAX показано, как Web-страница может оперативно общаться с Web-сервером, когда пользователь вводит данные в Web-форму.</p><section id="13.section.10"><p>На странице выводится поле ввода с предложением ввести имя. Когда пользователь начинает вводить в этом поле имя, ниже появляются  возможные варианты имен.</p></section><section id="13.section.11"><p>Пусть  на Web-странице имеется форма HTML со следующим кодом: </p><empty-line/><p id="">&lt;form&gt; </p><p>
Имя:</p><p>
&lt;input type="text" id="txt1"</p><p>
onkeyup="showHint(this.value)"&gt;</p><p>
&lt;/form&gt;</p><p>
&lt;p&gt;Советуем: &lt;span id="txtHint"&gt;&lt;/span&gt;&lt;/p&gt; </p><empty-line/><p>Как можно видеть, это простая форма HTML с полем ввода с именем "txt1". </p><p>Атрибут события этого поля ввода определяет функцию, которая будет запускаться при возникновении события onkeyup. </p><p>Параграф ниже формы содержит тег <emphasis>span</emphasis> с именем "txtHint". Тег <emphasis>span</emphasis> используется в качестве поля для подстановки данных, получаемых с Web-сервера. </p><p>Когда пользователь вводит данные, выполняется функция с именем "showHint()". Выполнение функции запускается событием "onkeyup". Другими словами, всякий раз, когда пользователь убирает свой палец с клавиатуры внутри поля ввода (отпускает нажатую клавишу), вызывается функция <emphasis>showHint</emphasis>.  </p></section><section id="13.section.12"><p>Функция <emphasis>showHint()</emphasis> является очень простой функцией JavaScript, помещенной в раздел  заголовка <emphasis>&lt;head&gt;</emphasis> страницы HTML.</p><p>Функция имеет следующий код:</p><empty-line/><p id="">function showHint(str)</p><p>
{</p><p>
if (str.length==0)</p><p>
{ </p><p>
document.getElementById("txtHint").innerHTML=""</p><p>
return</p><p>
}</p><p>
xmlHttp=GetXmlHttpObject()</p><p>
if (xmlHttp==null)</p><p>
{</p><p>
alert ("Браузер не поддерживает запросы HTTP")</p><p>
return</p><p>
} </p><p>
var url="gethint.asp"</p><p>
url=url+"?q="+str</p><p>
url=url+"&amp;sid="+Math.random()</p><p>
xmlHttp.onreadystatechange=stateChanged </p><p>
xmlHttp.open("GET",url,true)</p><p>
xmlHttp.send(null)</p><p>
}</p><empty-line/><p>Функция выполняется всякий раз, когда в поле ввода вводится символ.</p><p>Если имеется какой-то ввод в текстовое поле (<emphasis>str.length &gt; 0</emphasis>), то функция выполняет следующее:</p><p><strong>
		[x].
        </strong>Определяет url (имя файла) для отправки на сервер </p><p><strong>
		[x].
        </strong>Добавляет к url параметр (<emphasis>q</emphasis>) с содержимым поля ввода </p><p><strong>
		[x].
        </strong>Добавляет случайное число, чтобы сервер не использовал кэшированный файл</p><p><strong>
		[x].
        </strong>Создает объект XMLHTTP, и приказывает объекту выполнить функцию с именем <emphasis>stateChanged</emphasis>, когда произойдет изменение.  </p><p><strong>
		[x].
        </strong>Открывает объект <emphasis>XMLHTTP</emphasis> с заданным url.</p><p><strong>
		[x].
        </strong>Посылает запрос HTTP на сервер </p><p>Если поле ввода будет пустым, то функция просто очищает содержимое поля для подстановки <emphasis>txtHint</emphasis>.</p></section><section id="13.section.13"><p>Функция <emphasis>stateChanged()</emphasis> содержит следующий код:</p><empty-line/><p id="">function stateChanged() </p><p>
{ </p><p>
if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")</p><p>
{ </p><p>
document.getElementById("txtHint").innerHTML=xmlHttp.responseText </p><p>
} </p><p>
} </p><empty-line/><p>Функция <emphasis>stateChanged()</emphasis> выполняется всякий раз, когда изменяется состояние объекта XMLHTTP.</p><p>Когда состояние будет равно 4 (или "complete"), поле для подстановки <emphasis>txtHint</emphasis> получает содержимое текста пришедшего ответа.</p></section></section></section><section id="13.section.14"><p>Приложения AJAX могут выполняться только в Web-браузерах с поддержкой XML.</p><section id="13.section.15"><p>Приложения AJAX могут выполняться только в Web-браузерах с полной поддержкой XML, т.е. всеми основными современными браузерами. </p><p>Предыдущий пример вызывает функцию с именем <emphasis>GetXmlHttpObject</emphasis>.</p><p>Эта функция предназначена для решения проблемы создания различных объектов <emphasis>XMLHTTP</emphasis> для различных браузеров. </p><p>Функция имеет следующий код:</p><empty-line/><p id="">function GetXmlHttpObject(handler)</p><p>
{ </p><p>
var objXMLHttp=null</p><p>
if (window.XMLHttpRequest)</p><p>
{</p><p>
objXMLHttp=new XMLHttpRequest()</p><p>
}</p><p>
else if (window.ActiveXObject)</p><p>
{</p><p>
objXMLHttp=new ActiveXObject("Microsoft.XMLHTTP")</p><p>
}</p><p>
return objXMLHttp</p><p>
}</p><empty-line/></section></section><section id="13.section.16"><p>Далее показан полный исходный код рассмотренного выше примера AJAX. </p><section id="13.section.17"><p>Эта страница HTML содержит простую форму HTML и ссылку на файл JavaScript.</p><empty-line/><p id="">&lt;html&gt;</p><p>
&lt;head&gt;</p><p>
&lt;script src="clienthint.js"&gt;&lt;/script&gt; </p><p>
&lt;/head&gt;</p><p>
&lt;body&gt;</p><p>
&lt;form&gt; </p><p>
Имя:</p><p>
&lt;input type="text" id="txt1"</p><p>
onkeyup="showHint(this.value)"&gt;</p><p>
&lt;/form&gt;</p><p>
&lt;p&gt;Советуем: &lt;span id="txtHint"&gt;&lt;/span&gt;&lt;/p&gt; </p><p>
&lt;/body&gt;</p><p>
&lt;/html&gt;</p><empty-line/></section><section id="13.section.18"><p>Это код JavaScript,  который находится в файле "clienthint.js":</p><empty-line/><p id="">var xmlHttp</p><p>
</p><p>
function showHint(str)</p><p>
{</p><p>
if (str.length==0)</p><p>
{ </p><p>
document.getElementById("txtHint").innerHTML=""</p><p>
return</p><p>
}</p><p>
xmlHttp=GetXmlHttpObject()</p><p>
if (xmlHttp==null)</p><p>
{</p><p>
alert ("Браузер не поддерживает запросы HTTP")</p><p>
return</p><p>
} </p><p>
var url="gethint.asp"</p><p>
url=url+"?q="+str</p><p>
url=url+"&amp;sid="+Math.random()</p><p>
xmlHttp.onreadystatechange=stateChanged </p><p>
xmlHttp.open("GET",url,true)</p><p>
xmlHttp.send(null)</p><p>
} </p><p>
</p><p>
function stateChanged() </p><p>
{ </p><p>
if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")</p><p>
{ </p><p>
document.getElementById("txtHint").innerHTML=xmlHttp.responseText </p><p>
} </p><p>
} </p><p>
</p><p>
function GetXmlHttpObject()</p><p>
{ </p><p>
var objXMLHttp=null</p><p>
if (window.XMLHttpRequest)</p><p>
{</p><p>
objXMLHttp=new XMLHttpRequest()</p><p>
}</p><p>
else if (window.ActiveXObject)</p><p>
{</p><p>
objXMLHttp=new ActiveXObject("Microsoft.XMLHTTP")</p><p>
}</p><p>
return objXMLHttp</p><p>
} </p><empty-line/><p>Далее речь пойдет о серверной странице AJAX.</p></section><section id="13.section.19"><p>Сервера AJAX не существует.</p><p>Страницы AJAX может обрабатывать любой сервер Интернет.</p><section id="13.section.20"><p>Серверная страница, вызываемая сценарием JavaScript в рассматриваемом примере, является простым файлом ASP с именем "gethint.asp".</p><p>Ниже представлены два примера кода серверной страницы, один, написанный на ASP, а другой – на PHP. </p></section><section id="13.section.21"><p>Код на странице "gethint.asp" написан на VBScript для Информационного сервера Интернет (IIS). Он просто проверяет массив имен и возвращает клиенту подходящие имена:</p><empty-line/><p id="">&lt;%</p><p>
dim a(30)</p><p>
'Заполнение массива именами </p><p>
a(1)="Anna"</p><p>
a(2)="Brittany"</p><p>
a(3)="Cinderella"</p><p>
a(4)="Diana"</p><p>
a(5)="Eva"</p><p>
a(6)="Fiona"</p><p>
a(7)="Gunda"</p><p>
a(8)="Hege"</p><p>
a(9)="Inga"</p><p>
a(10)="Johanna"</p><p>
a(11)="Kitty"</p><p>
a(12)="Linda"</p><p>
a(13)="Nina"</p><p>
a(14)="Ophelia"</p><p>
a(15)="Petunia"</p><p>
a(16)="Amanda"</p><p>
a(17)="Raquel"</p><p>
a(18)="Cindy"</p><p>
a(19)="Doris"</p><p>
a(20)="Eve"</p><p>
a(21)="Evita"</p><p>
a(22)="Sunniva"</p><p>
a(23)="Tove"</p><p>
a(24)="Unni"</p><p>
a(25)="Violet"</p><p>
a(26)="Liza"</p><p>
a(27)="Elizabeth"</p><p>
a(28)="Ellen"</p><p>
a(29)="Wenche"</p><p>
a(30)="Vicky"</p><p>
'извлечение параметра q из URL</p><p>
q=ucase(request.querystring("q"))</p><p>
'поиск всех рекомендаций из массива, если длина q&gt;0</p><p>
if len(q)&gt;0 then</p><p>
  hint=""</p><p>
  for i=1 to 30</p><p>
    if q=ucase(mid(a(i),1,len(q))) then</p><p>
      if hint="" then</p><p>
        hint=a(i)</p><p>
      else</p><p>
        hint=hint &amp; " , " &amp; a(i)</p><p>
      end if</p><p>
    end if</p><p>
  next</p><p>
end if</p><p>
'Вывод "нет предложений" если рекомендуемого имени не найдено </p><p>
'или вывод подходящих значений </p><p>
if hint="" then </p><p>
  response.write("нет предложений")</p><p>
else</p><p>
  response.write(hint)</p><p>
end if</p><p>
%&gt;</p><empty-line/></section><section id="13.section.22"><p>Приведенный выше код переписан на PHP.</p><p>Примечание: Чтобы выполнить весь пример на PHP, не забудьте изменить значение переменной url в "clienthint.js" с "gethint.asp" на "gethint.php".</p></section><section id="13.section.23"><empty-line/><p id="">&lt;?php</p><p>
// Заполняем массив именами </p><p>
$a[]="Anna";</p><p>
$a[]="Brittany";</p><p>
$a[]="Cinderella";</p><p>
$a[]="Diana";</p><p>
$a[]="Eva";</p><p>
$a[]="Fiona";</p><p>
$a[]="Gunda";</p><p>
$a[]="Hege";</p><p>
$a[]="Inga";</p><p>
$a[]="Johanna";</p><p>
$a[]="Kitty";</p><p>
$a[]="Linda";</p><p>
$a[]="Nina";</p><p>
$a[]="Ophelia";</p><p>
$a[]="Petunia";</p><p>
$a[]="Amanda";</p><p>
$a[]="Raquel";</p><p>
$a[]="Cindy";</p><p>
$a[]="Doris";</p><p>
$a[]="Eve";</p><p>
$a[]="Evita";</p><p>
$a[]="Sunniva";</p><p>
$a[]="Tove";</p><p>
$a[]="Unni";</p><p>
$a[]="Violet";</p><p>
$a[]="Liza";</p><p>
$a[]="Elizabeth";</p><p>
$a[]="Ellen";</p><p>
$a[]="Wenche";</p><p>
$a[]="Vicky";</p><p>
//извлечение параметра q из URL</p><p>
$q=$_GET["q"];</p><p>
//поиск всех рекомендаций в массиве, если длина q&gt;0</p><p>
if (strlen($q) &gt; 0)</p><p>
{</p><p>
  $hint="";</p><p>
  for($i=0; $i&lt;count($a); $i++)</p><p>
  {</p><p>
  if (strtolower($q)==strtolower(substr($a[$i],0,strlen($q))))</p><p>
    {</p><p>
    if ($hint=="")</p><p>
      {</p><p>
      $hint=$a[$i];</p><p>
      }</p><p>
    else</p><p>
      {</p><p>
      $hint=$hint." , ".$a[$i];</p><p>
      }</p><p>
    }</p><p>
  }</p><p>
}</p><p>
</p><p>
// Вывод "нет предложений", если рекомендаций не найдено </p><p>
// или вывод подходящих значений </p><p>
if ($hint == "")</p><p>
{</p><p>
$response="нет предложений";</p><p>
}</p><p>
else</p><p>
{</p><p>
$response=$hint;</p><p>
}</p><p>
</p><p>
//вывод ответа </p><p>
echo $response;</p><p>
?&gt;</p><empty-line/></section></section></section><section id="13.section.24"><p>AJAX можно использовать для интерактивного взаимодействия с базой данных.</p><section id="13.section.25"><p>В следующем примере приложения AJAX будет показано, как Web-страница может извлекать информацию из базы данных с помощью технологии AJAX. </p><section id="13.section.26"><p>На Web-странице выводится список выбора с именами клиентов. </p><p>При выборе любого клиента на странице выводится связанная с ним информация из базы данных </p></section></section><section id="13.section.27"><p>Описанный выше пример страницы содержит простую форму HTML и ссылку на сценарий JavaScript:</p><empty-line/><p id="">&lt;html&gt;</p><p>
&lt;head&gt;</p><p>
&lt;script src="selectcustomer.js"&gt;&lt;/script&gt;</p><p>
&lt;/head&gt;</p><p>
&lt;body&gt;</p><p>
&lt;form&gt; </p><p>
Выберите заказчика:</p><p>
&lt;select name="customers" onchange="showCustomer(this.value)"&gt;</p><p>
&lt;option value="ALFKI"&gt;Alfreds Futterkiste</p><p>
&lt;option value="NORTS "&gt;North/South</p><p>
&lt;option value="WOLZA"&gt;Wolski Zajazd </p><p>
&lt;/select&gt;</p><p>
&lt;/form&gt;</p><p>
&lt;p&gt;</p><p>
&lt;div id="txtHint"&gt;&lt;b&gt;Информация о заказчике будет выводиться здесь.&lt;/b&gt;&lt;/div&gt;</p><p>
&lt;/p&gt;</p><p>
&lt;/body&gt;</p><p>
&lt;/html&gt;</p><empty-line/><p>Как можно видеть, это просто форма HTML с раскрывающимся списком с названием "customers".</p><p>Параграф ниже формы содержит тег <emphasis>div</emphasis> с именем "txtHint". Тег div используется в качестве поля для заполнения получаемой с Web-сервера информацией.</p><p>Когда пользователь выбирает данные (имя заказчика), выполняется функция "showCustomer()". Выполнение функции запускается событием "onchange". Другими словами, каждый раз, когда пользователь изменяет значение в  поле раскрывающегося списка, вызывается функция <emphasis>showCustomer</emphasis>.</p><p>Код JavaScript показан далее.</p></section><section id="13.section.28"><p>Следующий далее код JavaScript находится в файле "selectcustomer.js":</p><empty-line/><p id="">var xmlHttp</p><p>
</p><p>
function showCustomer(str)</p><p>
{ </p><p>
xmlHttp=GetXmlHttpObject()</p><p>
if (xmlHttp==null)</p><p>
{</p><p>
alert ("Браузер не поддерживает запросы HTTP")</p><p>
return</p><p>
} </p><p>
var url="getcustomer.asp"</p><p>
url=url+"?q="+str</p><p>
url=url+"&amp;sid="+Math.random()</p><p>
xmlHttp.onreadystatechange=stateChanged </p><p>
xmlHttp.open("GET",url,true)</p><p>
xmlHttp.send(null)</p><p>
}</p><p>
</p><p>
function stateChanged() </p><p>
{ </p><p>
if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")</p><p>
{ </p><p>
document.getElementById("txtHint").innerHTML=xmlHttp.responseText </p><p>
} </p><p>
} </p><p>
</p><p>
function GetXmlHttpObject()</p><p>
{ </p><p>
var objXMLHttp=null</p><p>
if (window.XMLHttpRequest)</p><p>
{</p><p>
objXMLHttp=new XMLHttpRequest()</p><p>
}</p><p>
else if (window.ActiveXObject)</p><p>
{</p><p>
objXMLHttp=new ActiveXObject("Microsoft.XMLHTTP")</p><p>
}</p><p>
return objXMLHttp</p><p>
}</p><empty-line/></section><section id="13.section.29"><p>Серверная страница, вызываемая сценарием JavaScript, является просто файлом ASP file с именем "getcustomer.asp".</p><p>Страница написана на VBScript для Информационного сервера Интернет (IIS). Ее можно легко переписать на PHP, или любой другой серверный язык.</p><p>Код выполняет команды SQL на базе данных и возвращает результат в виде таблицы HTML:</p><empty-line/><p id="">sql="SELECT * FROM CUSTOMERS WHERE CUSTOMERID="</p><p>
sql=sql &amp; request.querystring("q")</p><p>
</p><p>
set conn=Server.CreateObject("ADODB.Connection")</p><p>
conn.Provider="Microsoft.Jet.OLEDB.4.0"</p><p>
conn.Open(Server.Mappath("/db/northwind.mdb"))</p><p>
set rs = Server.CreateObject("ADODB.recordset")</p><p>
rs.Open sql, conn</p><p>
</p><p>
response.write("&lt;table&gt;")</p><p>
do until rs.EOF</p><p>
for each x in rs.Fields</p><p>
response.write("&lt;tr&gt;&lt;td&gt;&lt;b&gt;" &amp; x.name &amp; "&lt;/b&gt;&lt;/td&gt;")</p><p>
response.write("&lt;td&gt;" &amp; x.value &amp; "&lt;/td&gt;&lt;/tr&gt;")</p><p>
next</p><p>
rs.MoveNext</p><p>
loop</p><p>
</p><p>
response.write("&lt;/table&gt;")</p><empty-line/></section></section><section id="13.section.30"><p>AJAX можно использовать для интерактивного взаимодействия с файлом XML.</p><section id="13.section.31"><p>В следующем далее примере приложения AJAX показано, как Web-страница может извлекать информацию из файла XML с помощью технологии AJAX.</p><section id="13.section.32"><p>На Web-странице выводится список выбора с именами исполнителей музыкальных произведений. При выборе исполнителя на странице появляется информация с описанием компакт-диска с записями этого музыканта. </p></section></section><section id="13.section.33"><p>Рассматриваемый пример содержит простую форму HTML и ссылку на  код JavaScript:</p><empty-line/><p id="">&lt;html&gt;</p><p>
&lt;head&gt;</p><p>
&lt;script src="selectcd.js"&gt;&lt;/script&gt;</p><p>
&lt;/head&gt;</p><p>
&lt;body&gt;</p><p>
&lt;form&gt;</p><p>
Выберите компакт-диск:</p><p>
&lt;select name="cds" onchange="showCD(this.value)"&gt;</p><p>
&lt;option value="Bob Dylan"&gt;Bob Dylan&lt;/option&gt;</p><p>
&lt;option value="Bonnie Tyler"&gt;Bonnie Tyler&lt;/option&gt;</p><p>
&lt;option value="Dolly Parton"&gt;Dolly Parton&lt;/option&gt; </p><p>
&lt;/select&gt;</p><p>
&lt;/form&gt;</p><p>
&lt;p&gt;</p><p>
&lt;div id="txtHint"&gt;&lt;b&gt;Здесь выводится информация о компакт-диске.&lt;/b&gt;&lt;/div&gt;</p><p>
&lt;/p&gt;</p><p>
&lt;/body&gt;</p><p>
&lt;/html&gt;</p><empty-line/><p>Как можно видеть, это простая форма HTML с простым раскрывающимся списком выбора с именем "cds".</p><p>Параграф ниже формы содержит тег <emphasis>div</emphasis> с именем "txtHint". Тег div используется в качестве поля для заполнения информацией, получаемой с Web-сервера. </p><p>Когда пользователь делает свой выбор, выполняется функция с именем  "showCD". Выполнение функции  запускается событием "onchange". Другими словами,  каждый раз, когда пользователь изменяет значение в поле раскрывающегося списка, вызывается функция <emphasis>showCD</emphasis>. </p><p>Код JavaScript показан далее.</p></section><section id="13.section.34"><p>Следующий далее код JavaScript находится в файле "selectcd.js":</p><empty-line/><p id="">var xmlHttp</p><p>
</p><p>
function showCD(str)</p><p>
{ </p><p>
xmlHttp=GetXmlHttpObject()</p><p>
if (xmlHttp==null)</p><p>
{</p><p>
alert ("Браузер не поддерживает запросы HTTP")</p><p>
return</p><p>
} </p><p>
var url="getcd.asp"</p><p>
url=url+"?q="+str</p><p>
url=url+"&amp;sid="+Math.random()</p><p>
xmlHttp.onreadystatechange=stateChanged </p><p>
xmlHttp.open("GET",url,true)</p><p>
xmlHttp.send(null)</p><p>
}</p><p>
</p><p>
function stateChanged() </p><p>
{ </p><p>
if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")</p><p>
{ </p><p>
document.getElementById("txtHint").innerHTML=xmlHttp.responseText </p><p>
} </p><p>
} </p><p>
</p><p>
function GetXmlHttpObject()</p><p>
{ </p><p>
var objXMLHttp=null</p><p>
if (window.XMLHttpRequest)</p><p>
{</p><p>
objXMLHttp=new XMLHttpRequest()</p><p>
}</p><p>
else if (window.ActiveXObject)</p><p>
{</p><p>
objXMLHttp=new ActiveXObject("Microsoft.XMLHTTP")</p><p>
}</p><p>
return objXMLHttp</p><p>
}</p><empty-line/></section><section id="13.section.35"><p>Серверная страница, вызываемая кодом JavaScript, будет простым файлом ASP с именем "getcd.asp".</p><p>Страница написана на VBScript для Информационного сервера Интернет (IIS). Ее можно легко переписать на PHP, или любом другом серверном языке.</p><p>Код выполняет запрос на файле XML и возвращает результат в виде HTML.</p><empty-line/><p id="">q=request.querystring("q")</p><p>
</p><p>
set xmlDoc=Server.CreateObject("Microsoft.XMLDOM")</p><p>
xmlDoc.async="false"</p><p>
xmlDoc.load(Server.MapPath("cd_catalog.xml"))</p><p>
</p><p>
set nodes=xmlDoc.selectNodes("CATALOG/CD[ARTIST='" &amp; q &amp; "']")</p><p>
</p><p>
for each x in nodes</p><p>
for each y in x.childnodes</p><p>
response.write("&lt;b&gt;" &amp; y.nodename &amp; ":&lt;/b&gt; ")</p><p>
response.write(y.text)</p><p>
response.write("&lt;br /&gt;")</p><p>
next</p><p>
next</p><empty-line/></section></section><section id="13.section.36"><p>Объект <emphasis>XMLHttpRequest</emphasis> делает возможной технологию AJAX.</p><section id="13.section.37"><p>Чтобы создавать Web-приложения AJAX, необходимо хорошо знать объект JavaScript, называемый <emphasis>XMLHttpRequest</emphasis>.</p><p>Объект <emphasis>XMLHttpRequest</emphasis> является ключевым понятием технологии AJAX. Он был доступен с момента появления в июле 2000 браузера Internet Explorer 5.5, но не был полностью понят до 2005 года, когда начались разговоры об AJAX и Web 2.0. </p><p>Ниже представлены некоторые методы и свойства этого объекта, с которыми необходимо быть знакомым.</p></section><section id="13.section.38"><p>Различные браузеры используют для создания объекта <emphasis>XMLHttpRequest</emphasis> различные методы.</p><p>Internet Explorer использует ActiveXObject.</p><p>Другие браузеры используют встроенный в JavaScript объект, называемый <emphasis>XMLHttpRequest</emphasis>.</p><p>Вот простейший код, который можно использовать, чтобы обойти эту проблему.</p><empty-line/><p id="">var XMLHttp=null</p><p>
</p><p>
if (window.XMLHttpRequest)</p><p>
  {</p><p>
  XMLHttp=new XMLHttpRequest()</p><p>
  }</p><p>
else if (window.ActiveXObject)</p><p>
  {</p><p>
  XMLHttp=new ActiveXObject("Microsoft.XMLHTTP")</p><p>
  }</p><empty-line/><section id="13.section.39"><p>Сначала создается переменная <emphasis>XMLHttp</emphasis> для использования в  качестве объекта <emphasis>XMLHttpRequest</emphasis>. Ее значение задается как <emphasis>null</emphasis>.</p><p>Затем проверяется, доступен ли объект <emphasis>window.XMLHttpRequest</emphasis>. Этот объект доступен в более новых версиях браузеров, таких как Firefox, Mozilla, и Opera.</p><p>Если объект доступен, то он используется для создания нового объекта.</p><empty-line/><p id="">XMLHttp=new XMLHttpRequest(). </p><empty-line/><p>Если он не доступен, то проверяется, доступен ли объект <emphasis>window.ActiveXObject</emphasis>. Этот объект будет доступен в браузере Internet Explorer версии 5.5 и выше.</p><p>Если этот объект доступен, то он используется для создания нового объекта:</p><empty-line/><p id="">XMLHttp=new ActiveXObject(). </p><empty-line/></section></section><section id="13.section.40"><p>Некоторые программисты предпочтут использовать самую новую и быструю версию  объекта <emphasis>XMLHttpRequest</emphasis>. </p><p>Следующий пример пытается использовать самую последнюю версию объекта "Msxml2.XMLHTTP" компании Microsoft, доступную в Internet Explorer 6, прежде чем обратиться к объекту "Microsoft.XMLHTTP", доступному в Internet Explorer 5.5 и выше. </p><empty-line/><p id="">var XMLHttp=null</p><p>
try</p><p>
{</p><p>
XMLHttp=new ActiveXObject("Msxml2.XMLHTTP")</p><p>
}</p><p>
catch(e)</p><p>
 {</p><p>
 try</p><p>
 {</p><p>
 XMLHttp=new ActiveXObject("Microsoft.XMLHTTP")</p><p>
 }</p><p>
}</p><p>
</p><p>
if (XMLHttp==null)</p><p>
{</p><p>
XMLHttp=new XMLHttpRequest()</p><p>
}</p><empty-line/><section id="13.section.41"><p>Сначала создается переменная <emphasis>XMLHttp</emphasis> для использования в качестве объекта <emphasis>XMLHttpRequest</emphasis>. Ее значение задается как <emphasis>null</emphasis>.</p><p>Затем делается попытка создания объекта способом компании Microsoft, доступным в Internet Explorer 6 и более поздних версиях:</p><empty-line/><p id="">XMLHttp=new ActiveXObject("Msxml2.XMLHTTP")</p><empty-line/><p>Если это порождает ошибку, то используется старый способ (Internet Explorer 5.5): </p><empty-line/><p id="">XMLHttp=new ActiveXObject("Microsoft.XMLHTTP")</p><empty-line/><p>Если <emphasis>XMLHttp</emphasis> по прежнему имеет значение <emphasis>null</emphasis>, то делается попытка создания объекта "стандартным" способом:</p><empty-line/><p id="">XMLHttp=new XMLHttpRequest()</p><empty-line/></section></section><section id="13.section.42"><p><strong>Метод open()</strong></p><p>Метод <emphasis>open()</emphasis> создает запрос для Web-сервера. </p><p><strong>Метод send()</strong></p><p>Метод <emphasis>send()</emphasis> посылает запрос серверу. </p><p><strong>Метод abort()</strong></p><p>Метод <emphasis>abort()</emphasis> отменяет текущий запрос к серверу.</p></section><section id="13.section.43"><p>Свойство <emphasis>readyState</emphasis> определяет текущее состояние объекта <emphasis>XMLHttpRequest</emphasis>.</p><p>В таблице показаны возможные значения свойства <emphasis>readyState</emphasis>:</p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">Состояние</th><th valign="top" bgcolor="#d8d8d8">Описание</th></tr><tr><td valign="top" bgcolor="#eaeaea">0</td><td valign="top" bgcolor="#eaeaea">Запрос не инициализирован</td></tr><tr><td valign="top" bgcolor="#eaeaea">1</td><td valign="top" bgcolor="#eaeaea">Запрос создан</td></tr><tr><td valign="top" bgcolor="#eaeaea">2</td><td valign="top" bgcolor="#eaeaea">Запрос послан</td></tr><tr><td valign="top" bgcolor="#eaeaea">3</td><td valign="top" bgcolor="#eaeaea">Запрос обрабатывается</td></tr><tr><td valign="top" bgcolor="#eaeaea">4</td><td valign="top" bgcolor="#eaeaea">Запрос завершен</td></tr></table></p><p><emphasis>readyState=0</emphasis> после создания объекта <emphasis>XMLHttpRequest</emphasis>, но до вызова метода <emphasis>open()</emphasis>.</p><p><emphasis>readyState=1</emphasis> после вызова метода <emphasis>open()</emphasis>, но до вызова метода <emphasis>send()</emphasis>.</p><p><emphasis>readyState=2</emphasis> после вызова метода <emphasis>send()</emphasis>.</p><p><emphasis>readyState=3</emphasis> после того, как браузер соединится с сервером, но до завершения сервером ответа.</p><p><emphasis>readyState=4</emphasis> после завершения запроса и полного получения всех данных ответа с сервера.</p><p>Различные браузеры используют свойство состояния готовности по-разному. Не стоит рассчитывать, что все браузеры будут сообщать обо всех состояниях. Некоторые не сообщают о состоянии  0 и 1.</p><p>Для приложений AJAX представляет интерес фактически только состояние 4. Те есть, когда запрос завершен, и можно использовать полученные данные.</p></section><section id="13.section.44"><p>Свойство <emphasis>responseText</emphasis> содержит присланный сервером текст.</p></section></section></section><section id="14.lecture"><title><p>Дополнение.
 Учебное руководство по XHTML</p></title><annotation/><section id="14.section.1"><p>Язык XHTML является более строгой и четкой версией языка разметки HTML.</p><p>В данном руководстве рассмотрены различия между HTML и XHTML, а также показано, как преобразовать Web-сайт на использование XHTML.</p></section><section id="14.section.2"><p>Язык XHTML является более строгой и четкой версией языка HTML.</p><section id="14.section.3"><p>Для понимания изложенного материала необходимо знать язык HTML и основы создания Web-страниц.</p></section><section id="14.section.4"><p>XHTML является сокращением от английского EXtensible HyperText Markup Language, что означает "Расширяемый язык разметки гипертекста".</p><p>XHTML предназначен для замены HTML.</p><p>XHTML почти совпадает с HTML 4.01.</p><p>XHTML является более строгой и четкой версией языка HTML.</p><p>XHTML является языком HTML, определенным как приложение XML.</p><p>XHTML одобрен в качестве Рекомендации консорциумом W3C.</p></section><section id="14.section.5"><p>XHTML 1.0 был одобрен как Рекомендация W3C 26 января  2000 г..</p><p>W3C определяет XHTML как последнюю версию HTML. XHTML будет постепенно заменять HTML.</p></section><section id="14.section.6"><p>Язык XHTML совместим с HTML 4.01.</p><p>Все новые браузеры поддерживают XHTML.</p></section><section id="14.section.7"><p>XHTML является переработкой HTML 4.01 в соответствии с XML, и может сразу использоваться существующими браузерами при соблюдении нескольких простых правил.</p></section><section id="14.section.8"><p>Данное руководство рассматривает:</p><p><strong>
		[x].
        </strong>Почему необходимо использовать XHTML</p><p><strong>
		[x].
        </strong>Синтаксис XHTML</p><p><strong>
		[x].
        </strong>Как преобразовать сайт на XHTML</p><p><strong>
		[x].
        </strong>Проверка XHTML </p><p><strong>
		[x].
        </strong>Модуляризация XHTML </p></section></section><section id="14.section.9"><p>XHTML является объединением HTML и XML (EXtensible Markup Language – Расширяемого языка разметки).</p><p>XHTML состоит из всех элементов HTML 4.01, объединенных с синтаксисом XML.</p><section id="14.section.10"><p>В настоящее время многие страницы в Интернет содержат "плохой" код HTML.</p><p>Следующий код  HTML будет нормально работать при просмотре в браузере, даже хотя он не полностью следует правилам HTML:</p><empty-line/><p id="">&lt;html&gt;</p><p>
&lt;head&gt;</p><p>
&lt;title&gt;Это плохой код HTML&lt;/title&gt;</p><p>
&lt;body&gt;</p><p>
&lt;h1&gt;Плохой код HTML</p><p>
&lt;/body&gt;</p><empty-line/><p>XML является языком разметки, в котором каждый элемент должен быть правильно размечен, что приводит к "грамматически-правильным" ("well-formed") документам.</p><p>Язык XML предназначен для описания данных, а язык HTML создан для представления данных.</p><p>На современном рынке представлены различные технологии браузеров, одни браузеры предназначены для использования Интернет на компьютерах, другие для использования Интернет на мобильных телефонах и c помощью карманных коммуникаторов. Последние устройства имеют недостаточно ресурсов или  мощности для интерпретации "плохого" языка разметки.</p><p>Объединяя сильные стороны HTML и XML, мы получаем язык разметки, который будет полезен сегодня и в будущем -- XHTML.</p><p>Страницы XHTML можно читать с помощью любых устройств, которые поддерживают XML.  Пока весь мир не перейдет на использование поддерживающих XML браузеров, XHTML предоставляет возможность сейчас писать "синтаксически-правильные" документы, которые можно использовать во всех браузерах.</p></section></section><section id="14.section.11"><p>XHTML можно начать использовать просто строго следуя правилам HTML.</p><section id="14.section.12"><p>XHTML не очень существенно отличается от стандарта HTML 4.01.</p><p>Поэтому хорошим началом будет приведение кода к стандарту 4.01.</p><p>Кроме того, необходимо писать код HTML символами нижнего регистра, и никогда не пропускать завершающие теги (такие как <emphasis>&lt;/p&gt;</emphasis>).</p><p>Вот собственно и все. Удачного кодирования!</p></section><section id="14.section.13"><p>Элементы XHTML должны быть правильно вложены</p><p>Элементы XHTML всегда должны быть замкнутыми</p><p>Элементы XHTML должны записываться в нижнем регистре</p><p>Документы XHTML должны иметь один корневой элемент</p></section><section id="14.section.14"><p>В HTML некоторые элементы могут вкладываться друг в друга некорректно, например как в случае: <emphasis>&lt;b&gt;&lt;i&gt;Этот текст жирный и наклонный&lt;/b&gt;&lt;/i&gt;</emphasis></p><p>В XHTML все элементы должны правильно вкладываться друг в друга, например: <emphasis>&lt;b&gt;&lt;i&gt;Этот текст жирный и наклонный&lt;/i&gt;&lt;/b&gt;</emphasis></p><p><strong>Примечание:</strong> Достаточно часто при создании вложенных списков забывают о том, что внутренний список должен находится между тегами <emphasis>&lt;li&gt;</emphasis> и <emphasis>&lt;/li&gt;</emphasis>.</p><p>Неправильно:</p><empty-line/><p id="">&lt;ul&gt;</p><p>
  &lt;li&gt;Кофе&lt;/li&gt;</p><p>
  &lt;li&gt;Чай</p><p>
    &lt;ul&gt;</p><p>
      &lt;li&gt;Черный чай&lt;/li&gt;</p><p>
      &lt;li&gt;Зеленый чай&lt;/li&gt;</p><p>
    &lt;/ul&gt;</p><p>
  &lt;li&gt;Молоко&lt;/li&gt;</p><p>
&lt;/ul&gt;</p><empty-line/><p>Правильно:</p><empty-line/><p id="">&lt;ul&gt;</p><p>
  &lt;li&gt;Кофе&lt;/li&gt;</p><p>
  &lt;li&gt;Чай</p><p>
    &lt;ul&gt;</p><p>
      &lt;li&gt;Черный чай&lt;/li&gt;</p><p>
      &lt;li&gt;Зеленый чай&lt;/li&gt;</p><p>
    &lt;/ul&gt;</p><p>
  &lt;/li&gt;</p><p>
  &lt;li&gt;Молоко&lt;/li&gt;</p><p>
&lt;/ul&gt;</p><empty-line/><p>Обратите внимание, что в примере "правильного" кода вставлен тег <emphasis>&lt;/li&gt;</emphasis> после тега <emphasis>&lt;/ul&gt;</emphasis>.</p></section><section id="14.section.15"><p>Непустые элементы должны иметь замыкающий тег.</p><p>Неправильно:</p><empty-line/><p id="">&lt;p&gt;Это -- параграф </p><p>
&lt;p&gt;Это -- еще один параграф</p><empty-line/><p>Правильно:</p><empty-line/><p id="">&lt;p&gt;Это -- параграф &lt;/p&gt;</p><p>
&lt;p&gt;Это -- еще один параграф &lt;/p&gt;</p><empty-line/></section><section id="14.section.16"><p>Пустые элементы должны иметь замыкающий тег или начальный тег должен заканчиваться символами <emphasis>/&gt;</emphasis>.</p><p>Неправильно:</p><empty-line/><p id="">Разрыв строки: &lt;br&gt;</p><p>
Горизонтальная линия: &lt;hr&gt;</p><p>
Изображение: &lt;img src="happy.gif" alt="Веселое лицо "&gt;</p><empty-line/><p>Правильно:</p><empty-line/><p id="">Разрыв строки: &lt;br /&gt;</p><p>
Горизонтальная линия: &lt;hr /&gt;</p><p>
Изображение: &lt;img src="happy.gif" alt="Веселое лицо " /&gt;</p><empty-line/></section><section id="14.section.17"><p>Спецификация XHTML определяет, что имена и атрибуты тегов должны записываться в нижнем регистре.</p><p>Неправильно:</p><empty-line/><p id="">&lt;BODY&gt;</p><p>
&lt;P&gt;Параграф &lt;/P&gt;</p><p>
&lt;/BODY&gt;</p><empty-line/><p>Правильно:</p><empty-line/><p id="">&lt;body&gt;</p><p>
&lt;p&gt;Параграф &lt;/p&gt;</p><p>
&lt;/body&gt;</p><empty-line/></section><section id="14.section.18"><p>Все элементы XHTML должны быть вложены в корневой элемент <emphasis>&lt;html&gt;</emphasis>. Все другие элементы могут иметь вложенные элементы (потомков). Вложенные элементы должны быть парными и правильно вкладываться в свой родительский элемент. Общая структура документа имеет следующий вид: 	</p><empty-line/><p id="">&lt;html&gt;</p><p>
&lt;head&gt; ... &lt;/head&gt;</p><p>
&lt;body&gt; ... &lt;/body&gt;</p><p>
&lt;/html&gt;</p><empty-line/></section></section><section id="14.section.19"><p>При записи документа XHTML требуется использовать четкий синтаксис HTML.</p><section id="14.section.20"><p><strong>
		[x].
        </strong>Имена атрибутов должны записываться в нижнем регистре </p><p><strong>
		[x].
        </strong>Значения атрибутов должны заключаться в кавычки </p><p><strong>
		[x].
        </strong>Минимизация атрибутов запрещена </p><p><strong>
		[x].
        </strong>Атрибут <emphasis>id</emphasis> заменяет атрибут name </p><p><strong>
		[x].
        </strong>DTD XHTML определяет обязательные элементы</p></section><section id="14.section.21"><p>Неправильно:</p><empty-line/><p id="">&lt;table WIDTH="100%"&gt;</p><empty-line/><p>Правильно:</p><empty-line/><p id="">&lt;table width="100%"&gt;</p><empty-line/></section><section id="14.section.22"><p>Неправильно:</p><empty-line/><p id="">&lt;table width=100%&gt;</p><empty-line/><p>Правильно:</p><empty-line/><p id="">&lt;table width="100%"&gt;</p><empty-line/></section><section id="14.section.23"><p>Неправильно:</p><empty-line/><p id="">&lt;input checked&gt;</p><p>
&lt;input readonly&gt;</p><p>
&lt;input disabled&gt;</p><p>
&lt;option selected&gt;</p><p>
&lt;frame noresize&gt;</p><empty-line/><p>Правильно:</p><empty-line/><p id="">&lt;input checked="checked" /&gt;</p><p>
&lt;input readonly="readonly" /&gt;</p><p>
&lt;input disabled="disabled" /&gt;</p><p>
&lt;option selected="selected" /&gt;</p><p>
&lt;frame noresize="noresize" /&gt;</p><empty-line/><p>Ниже представлен список минимизированных атрибутов HTML и их запись в XHTML.</p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">HTML</th><th valign="top" bgcolor="#d8d8d8">XHTML</th></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>compact</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>compact="compact"</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><p><emphasis>checked</emphasis></p> <p><emphasis>declare</emphasis></p></td><td valign="top" bgcolor="#eaeaea"><p><emphasis>checked="checked"</emphasis></p> <p><emphasis>declare="declare"</emphasis></p></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>readonly</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>readonly="readonly"</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>disabled</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>disabled="disabled"</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>selected</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>selected="selected"</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>defer</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>defer="defer"</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>ismap</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>ismap="ismap"</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>nohref</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>nohref="nohref"</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>noshade</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>noshade="noshade"</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>nowrap</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>nowrap="nowrap"</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>multiple</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>multiple="multiple"</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>noresize</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>noresize="noresize"</emphasis></td></tr></table></p></section><section id="14.section.24"><p>HTML 4.01 определяет атрибут <emphasis>name</emphasis> для элементов <emphasis>a, applet, frame, iframe, img, </emphasis> и <emphasis>map</emphasis>. В XHTML атрибут <emphasis>name</emphasis> исключен. Вместо него используется атрибут <emphasis>id</emphasis>.</p><p>Неправильно:</p><empty-line/><p id="">&lt;img src="picture.gif" name="рис. 1" /&gt;</p><empty-line/><p>Правильно:</p><empty-line/><p id="">&lt;img src="picture.gif" id="рис. 1" /&gt;</p><empty-line/><p><strong>Примечание:</strong> Для взаимодействия со старыми браузерами в течение некоторого времени необходимо будет использовать оба атрибута <emphasis>name</emphasis> и <emphasis>id</emphasis>, с одинаковыми значениями атрибутов, например: <emphasis>&lt;img src="picture.gif" id="рис. 1" name="рис. 1" /&gt;</emphasis>.</p></section><section id="14.section.25"><p>Для совместимости XHTML с современными браузерами, необходимо добавить дополнительный пробел перед символом "/".</p></section><section id="14.section.26"><p>Атрибут <emphasis>lang</emphasis> применим почти к любому элементу XHTML. Он определяет язык содержимого внутри элемента.</p><p>Если в каком-то элементе используется атрибут <emphasis>lang</emphasis>,  то необходимо добавить атрибут <emphasis>xml:lang</emphasis>, например:  <emphasis>&lt;div lang="fr" xml:lang="fr"&gt;Bonjour, madam!&lt;/div&gt;</emphasis>.</p></section><section id="14.section.27"><p>Все документы XHTML должны иметь объявление DOCTYPE. Также должны присутствовать элементы <emphasis>html, head и body</emphasis>, а внутри элемента <emphasis>head</emphasis> должен присутствовать элемент <emphasis>title</emphasis>.</p><p>Шаблон минимального документа XHTML имеет следующий вид:</p><empty-line/><p id="">&lt;!DOCTYPE Здесь определяется тип документа&gt;</p><p>
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;</p><p>
&lt;head&gt;</p><p>
&lt;title&gt;Здесь задается заголовок &lt;/title&gt;</p><p>
&lt;/head&gt;</p><p>
&lt;body&gt;</p><p>
&lt;/body&gt;</p><p>
&lt;/html&gt;</p><empty-line/><p><strong>Примечание:</strong> Объявление DOCTYPE не является частью самого документа XHTML. Это объявление не является элементом XHTML и не должно иметь закрывающий тег.</p><p><strong>Примечание:</strong> Атрибут xmlns в теге <emphasis>&lt;html&gt;</emphasis> является в XHTML обязательным. Однако программа проверки (валидатор) на сайте w3.org не высказывает претензий, когда этот атрибут отсутствует в документе XHTML. Это обусловлено тем, что атрибут "xmlns=http://www.w3.org/1999/xhtml" имеет фиксированное значение и будет добавлен в тег <emphasis>&lt;html&gt;</emphasis>, даже если он не был включен.</p><p>В следующем разделе представлена дополнительная информация об определении типа документа XHTML.</p></section></section><section id="14.section.28"><p>Стандарт XHTML определяет три определения типа документа (Document Type Definitions – DTD).</p><p>Наиболее распространенным является XHTML Transitional (Переходный).</p><section id="14.section.29"><p>Документ XHTML состоит из трех основных частей:</p><p>Тип документа DOCTYPE</p><p>Заголовок (Head)</p><p>Тело (Body)</p><p>Базовая структура документа имеет следующий вид:</p><empty-line/><p id="">&lt;!DOCTYPE ...&gt;</p><p>
&lt;html&gt;</p><p>
&lt;head&gt;</p><p>
&lt;title&gt;... &lt;/title&gt;</p><p>
&lt;/head&gt;</p><p>
&lt;body&gt; ... &lt;/body&gt;</p><p>
&lt;/html&gt;</p><empty-line/><p>Объявление DOCTYPE всегда должно присутствовать в первой строке документа XHTML.</p></section><section id="14.section.30"><p>Это простой (минимальный) документ XHTML:</p><empty-line/><p id="">&lt;!DOCTYPE html</p><p>
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"</p><p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;</p><p>
&lt;html&gt;</p><p>
&lt;head&gt;</p><p>
&lt;title&gt;простой документ &lt;/title&gt;</p><p>
&lt;/head&gt;</p><p>
&lt;body&gt;</p><p>
&lt;p&gt;простой параграф &lt;/p&gt;</p><p>
&lt;/body&gt;</p><p>
&lt;/html&gt;</p><empty-line/><p>Объявление DOCTYPE определяет тип документа:</p><empty-line/><p id="">&lt;!DOCTYPE html</p><p>
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"</p><p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;</p><empty-line/><p>Оставшаяся часть документа выглядит как HTML:</p><empty-line/><p id="">&lt;html&gt;</p><p>
&lt;head&gt;</p><p>
&lt;title&gt;простой документ &lt;/title&gt;</p><p>
&lt;/head&gt;</p><p>
&lt;body&gt;</p><p>
&lt;p&gt; простой параграф &lt;/p&gt;</p><p>
&lt;/body&gt;</p><p>
&lt;/html&gt;</p><empty-line/></section><section id="14.section.31"><p><strong>
		[x].
        </strong>DTD определяет синтаксис Web-страницы на SGML.</p><p><strong>
		[x].
        </strong>DTD используется приложениями SGML, такими как HTML, для определения правил, которые применяют при разметке документов определенного типа, включая множество объявлений элементов и сущностей.  </p><p><strong>
		[x].
        </strong>XHTML задан в определении типа документа SGML или 'DTD'.</p><p><strong>
		[x].
        </strong>DTD XHTML описывает точным, понятным для компьютера языком допустимый синтаксис и грамматику разметки XHTML.</p><p>В настоящее время имеется три типа документов XHTML:</p><p><strong>
		[x].
        </strong>STRICT</p><p><strong>
		[x].
        </strong>TRANSITIONAL</p><p><strong>
		[x].
        </strong>FRAMESET</p><p>XHTML 1.0 определяет три типа документов XML, которые соответствуют трем DTD: Strict, Transitional, и Frameset.</p><section id="14.section.32"><empty-line/><p id="">&lt;!DOCTYPE html</p><p>
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" </p><p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;</p><empty-line/><p>Это определение DTD используется, когда требуется  получить действительно четкую разметку, не имеющую в представлении никакого беспорядка. Оно используется вместе с каскадными таблицами стилей.</p></section><section id="14.section.33"><empty-line/><p id="">&lt;!DOCTYPE html</p><p>
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"</p><p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;</p><empty-line/><p>Используйте это определение, когда надо воспользоваться средствами представления HTML, и когда необходимо обеспечить поддержку для браузеров, которые не понимают каскадные таблицы стилей.</p></section><section id="14.section.34"><empty-line/><p id="">&lt;!DOCTYPE html</p><p>
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"</p><p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"&gt;</p><empty-line/><p>Укажите это определение, когда будут использоваться фреймы HTML, чтобы разделить окно браузера на два или большее количество фреймов.</p></section></section></section><section id="14.section.35"><section id="14.section.36"><p>Чтобы преобразовать Web-сайт с языка HTML на XHTML, необходимо знать правила синтаксиса XHTML, которые были рассмотрены выше. Затем необходимо выполнить следующие действия (в указанном порядке):</p></section><section id="14.section.37"><p>В качестве первой строки каждой страницы  добавляют следующее объявление DOCTYPE:</p><empty-line/><p id="">&lt;!DOCTYPE html PUBLIC</p><p>
"-//W3C//DTD XHTML 1.0 Transitional//EN"</p><p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;</p><empty-line/><p>Лучше использовать сначала переходное определение DTD (Transitional). Можно выбрать и строгое определение DTD (Strict), но оно немного слишком "строгое" на начальном этапе, и ему труднее соответствовать.</p></section><section id="14.section.38"><p>Web-cтраницы должны иметь объявление DOCTYPE, если желательно, чтобы они были определены как правильные согласно XHTML.</p><p>Надо помнить, однако, что более новые браузеры (такие как Internet Explorer 6) могут обрабатывать документ по-разному, в зависимости от объявления  <emphasis>&lt;!DOCTYPE&gt;</emphasis>. Если браузер читает документ с DOCTYPE, то он может интерпретировать документ как "правильный". Плохо сформированный XHTML может выводиться иначе, чем при отсутствии DOCTYPE.</p></section><section id="14.section.39"><p>Так как XHTML различает регистр символов, и поскольку XHTML допускает имена тегов и атрибутов HTML только в нижнем регистре, то необходимо выполнить глобальный поиск и замену всех тегов в верхнем регистре тегами, записанными в нижнем регистре. Аналогичную процедуру необходимо выполнить также для имен атрибутов.</p></section><section id="14.section.40"><p>Так как рекомендация W3C для XTML 1.0 говорит, что значения всех атрибутов должны быть заключены в кавычки, то необходимо проверить все Web-страницы, чтобы значения всех атрибутов были правильно заключены в кавычки. Это трудоемкая работа, поэтому рекомендуется в будущем никогда не забывать использовать кавычки для значений атрибутов.</p></section><section id="14.section.41"><p>В XHTML пустые теги не разрешены. Теги <emphasis>&lt;hr&gt;</emphasis> и <emphasis>&lt;br&gt;</emphasis> должны быть заменены соответственно на <emphasis>&lt;hr /&gt;</emphasis> и <emphasis>&lt;br /&gt;</emphasis>.</p><p>Это создает проблему с браузером Netscape, который неправильно интерпретирует тег  <emphasis>&lt;br/&gt;</emphasis>. Но к счастью, по неизвестной причине, замена его на <emphasis>&lt;br /&gt;</emphasis> прекрасно работает. В этом случае также необходимо выполнить глобальный поиск и замену соответствующих тегов.</p><p>Некоторые другие теги (такие как тег <emphasis>&lt;img&gt;</emphasis>) страдают от такой же проблемы. В данном случае можно не использовать тег замыкания  <emphasis>&lt;/img&gt;</emphasis>, а добавить <emphasis>/&gt;</emphasis> в конце тега.</p></section><section id="14.section.42"><p>После выполнения всех преобразований все имеющиеся страницы проверяются согласно официальному DTD W3C с помощью следующей ссылки на XHTML Validator (<a l:href="">http://validator.w3.org/check/referer</a>). Возможные не выявленные на начальном этапе ошибки надо будет отредактировать вручную. Наиболее распространенной ошибкой бывает отсутствие в списках тегов замыкающего <emphasis>&lt;/li&gt;</emphasis>.</p><p>Имеются ли какие-либо специальные инструментальные средства для преобразования? Да, можно использовать утилиту TIDY.</p><p>Бесплатная утилита Дейва Рагетта HTML TIDY (<a l:href="">http://www.w3.org/People/Raggett/tidy/</a>) предназначена для проверки кода HTML. Она также отлично справляется с трудночитаемыми разметками документов, созданными специальными редакторами HTML и инструментальными средствами конвертации, и может помочь определить места кода, требующие дополнительного внимания, чтобы сделать Web-страницы более доступными для людей с физическими недостатками.</p></section></section><section id="14.section.43"><p>Документ XHTML проверяется согласно Определению типа документа.</p><section id="14.section.44"><p>Документ XHTML проверяют на соответствие определению типа документа (DTD). Прежде чем можно будет проверить файл XHTML, необходимо добавить в качестве первой строки правильный DTD.</p><p>Strict DTD содержит элементы и атрибуты, которые не были исключены и не связаны с фреймами:</p><empty-line/><p id="">!DOCTYPE html PUBLIC</p><p>
"-//W3C//DTD XHTML 1.0 Strict//EN"</p><p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"</p><p>
</p><p>
Transitional DTD содержит все из Strict DTD плюс исключенные элементы и атрибуты:</p><p>
</p><p>
!DOCTYPE html PUBLIC</p><p>
"-//W3C//DTD XHTML 1.0 Transitional//EN"</p><p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</p><p>
</p><p>
Frameset DTD содержит все из Transitional DTD плюс фреймы:</p><p>
</p><p>
!DOCTYPE html PUBLIC</p><p>
"-//W3C//DTD XHTML 1.0 Frameset//EN"</p><p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"</p><empty-line/><p>Простой документ XHTML имеет следующий вид:</p><empty-line/><p id="">&lt;!DOCTYPE html</p><p>
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"</p><p>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;</p><p>
&lt;html&gt;</p><p>
&lt;head&gt;</p><p>
&lt;title&gt;простой документ &lt;/title&gt;</p><p>
&lt;/head&gt;</p><p>
&lt;body&gt;</p><p>
&lt;p&gt;простой параграф &lt;/p&gt;</p><p>
&lt;/body&gt;</p><p>
&lt;/html&gt;</p><empty-line/></section></section><section id="14.section.45"><p>Модель модуляризации XHTML определяет модули XHTML.</p><section id="14.section.46"><p>XHTML является простым, но большим языком. XHTML содержит большинство функций, которые могут понадобиться Web-разработчику.</p><p>Для некоторых целей XHTML является слишком большим и сложным, а для других целей он слишком прост.</p><p>Разделяя XHTML на модули, консорциум W3C создал небольшие и строго определенные множества элементов XHTML, которые можно использовать отдельно для простых устройств, а также в соединении с другими стандартами XML в больших и более сложных приложениях.</p><p>Используя модульность XHTML, разработчики приложений могут:</p><p><strong>
		[x].
        </strong>Выбирать элементы, которые будут поддерживаться устройством, используя стандартные строительные блоки XHTML.</p><p><strong>
		[x].
        </strong>Добавлять в XHTML расширения, используя XML, и не нарушая стандарт XHTML.</p><p><strong>
		[x].
        </strong>Упрощать XHTML для таких устройств, как карманные компьютеры-коммуникаторы, мобильные телефоны, ТВ устройства, и устройства бытовой техники.</p><p><strong>
		[x].
        </strong>Расширять XHTML для сложных приложений, добавляя новые функции XML (такие как MathML, SVG, Voice and Multimedia).</p><p><strong>
		[x].
        </strong>Определять профили XHTML, такие как XHTML Basic (подмножество XHTML для мобильных устройств).</p></section><section id="14.section.47"><p>Консорциум W3C разделил определение XHTML на 28 модулей:</p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">Имя модуля</th><th valign="top" bgcolor="#d8d8d8">Описание</th></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Applet</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет исключенный элемент <emphasis>applet</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Base</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элемент <emphasis>base</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Basic Forms</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет базовые элементы форм </td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Basic Tables</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет базовые элементы таблиц  </td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Bi-directional Text</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элемент <emphasis>bdo</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Client Image Map</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы карт-изображений на стороне браузера</td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Edit</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы редактирования <emphasis>del</emphasis> и <emphasis>ins</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Forms</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет все элементы, используемые в формах</td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Frames</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы, связанные с фреймами </td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Hypertext</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элемент <emphasis>a</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Iframe</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элемент <emphasis>iframe</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Image</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элемент <emphasis>img</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Intrinsic Events</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет атрибуты событий, такие как <emphasis>onblur</emphasis> и <emphasis>onchange</emphasis> </td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Legacy</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет исключенные элементы и атрибуты</td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Link</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элемент <emphasis>link</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>List</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы списка  <emphasis>li, ul, dd, dt</emphasis>, и <emphasis>dl</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Metainformation</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элемент <emphasis>meta</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Name Identification</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет исключенный атрибут <emphasis>name</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Object</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы <emphasis>object</emphasis> и <emphasis>param</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Presentation</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы представления, такие как <emphasis>b</emphasis> и <emphasis>i</emphasis> </td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Scripting</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы <emphasis>script</emphasis> и <emphasis>noscript</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Server Image Map</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы карт-изображений на сервере</td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Structure</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы <emphasis>html, head, title</emphasis> и <emphasis>body</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Style Attribute</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет атрибут <emphasis>style</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Style Sheet</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элемент <emphasis>style</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Tables</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы, используемые в таблицах</td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Target</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет атрибут <emphasis>target</emphasis></td></tr><tr><td valign="top" bgcolor="#eaeaea">модуль <emphasis>Text</emphasis></td><td valign="top" bgcolor="#eaeaea">Определяет элементы контейнера текста, такие как <emphasis>p</emphasis> и <emphasis>h1</emphasis> </td></tr></table></p><p>Исключенные элементы не должны использоваться в XHTML.</p></section></section><section id="14.section.48"><p>Теги XHTML могут иметь атрибуты. Атрибуты каждого тега перечислены в описании тега. Здесь представлены базовые атрибуты и атрибуты языка, которые являются стандартными для всех тегов (с небольшими исключениями).</p><section id="14.section.49"><p>Недействительны в элементах <emphasis>base, head, html, meta, param, script, style</emphasis> и <emphasis>title</emphasis>.	</p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">Атрибут</th><th valign="top" bgcolor="#d8d8d8">Значение</th><th valign="top" bgcolor="#d8d8d8">Описание</th></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>class</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>правило_класса</emphasis> или <emphasis>правило_стиля</emphasis></td><td valign="top" bgcolor="#eaeaea">Класс элемента</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>id</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>имя_id</emphasis></td><td valign="top" bgcolor="#eaeaea">Уникальный id элемента</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>style</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>определение_стиля</emphasis></td><td valign="top" bgcolor="#eaeaea">Встроенное определение стиля</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>title</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>текст_подсказки</emphasis></td><td valign="top" bgcolor="#eaeaea">Текст для вывода подсказки</td></tr></table></p></section><section id="14.section.50"><p>Недействительны в элементах <emphasis>base, br, frame, frameset, hr, iframe, param</emphasis>, и <emphasis>script</emphasis>.</p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">Атрибут</th><th valign="top" bgcolor="#d8d8d8">Значение</th><th valign="top" bgcolor="#d8d8d8">Описание</th></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>dir</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>ltr | rtl</emphasis></td><td valign="top" bgcolor="#eaeaea">Задает направление текста</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>lang</emphasis></td><td valign="top" bgcolor="#eaeaea"><emphasis>код_языка</emphasis></td><td valign="top" bgcolor="#eaeaea">Задает код языка</td></tr></table></p></section><section id="14.section.51"><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">Атрибут</th><th valign="top" bgcolor="#d8d8d8">Значение</th><th valign="top" bgcolor="#d8d8d8">Описание</th></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>accesskey</emphasis></td><td valign="top" bgcolor="#eaeaea">символ</td><td valign="top" bgcolor="#eaeaea">Задает клавиатурное сокращение для доступа к элементу</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>tabindex</emphasis></td><td valign="top" bgcolor="#eaeaea">число</td><td valign="top" bgcolor="#eaeaea">Задает порядок элемента при переходе по клавише табуляции</td></tr></table></p></section></section><section id="14.section.52"><p>Новым в HTML 4.0 была возможность для событий HTML запускать в браузере действия, такие как запуск сценария JavaScript, когда пользователь щелкал на элементе HTML. Ниже  представлен список атрибутов, которые можно вставлять в теги HTML для определения действий событий.</p><p>Более подробно об использовании этих событий в программировании можно узнать в руководстве по JavaScript и руководстве по DHTML.</p><section id="14.section.53"><p>Действительны только в элементах <emphasis>body</emphasis> и <emphasis>frameset</emphasis></p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">Атрибут</th><th valign="top" bgcolor="#d8d8d8">Значение</th><th valign="top" bgcolor="#d8d8d8">Описание</th></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onload</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Сценарий, который выполняется при загрузке документа </td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onunload</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Сценарий, который выполняется при выгрузке документа</td></tr></table></p></section><section id="14.section.54"><p>Действительны только в элементах форм.</p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">Атрибут</th><th valign="top" bgcolor="#d8d8d8">Значение</th><th valign="top" bgcolor="#d8d8d8">Описание</th></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onchange</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Сценарий, который выполняется при изменении элемента</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onsubmit</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Сценарий, который выполняется при отправке формы</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onreset</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Сценарий, который выполняется при сбросе формы</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onselect</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Сценарий, который выполняется при выборе элемента</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onblur</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Сценарий, который выполняется, когда элемент теряет фокус</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onfocus</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Сценарий, который выполняется, когда элемент получает фокус</td></tr></table></p></section><section id="14.section.55"><p>Недействительны в элементах <emphasis>base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style</emphasis> и <emphasis>title</emphasis>.</p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">Атрибут</th><th valign="top" bgcolor="#d8d8d8">Значение</th><th valign="top" bgcolor="#d8d8d8">Описание</th></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onkeydown</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Действие после нажатия клавиши </td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onkeypress</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Действие после нажатия и отпускания клавиши </td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onkeyup</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Действие после отпускания клавиши</td></tr></table></p></section><section id="14.section.56"><p>Недействительны в элементах <emphasis>base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style</emphasis> и <emphasis>title</emphasis>.</p><p><table border="0" class="xml_table" cellpadding="2" cellspacing="1"><tr><th valign="top" bgcolor="#d8d8d8">Атрибут</th><th valign="top" bgcolor="#d8d8d8">Значение</th><th valign="top" bgcolor="#d8d8d8">Описание</th></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onclick</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Что делать при щелчке мыши</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>ondblclick</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Что делать при двойном щелчке мыши</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onmousedown</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Что делать при нажатии кнопки мыши</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onmousemove</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Что делать при перемещении указателя мыши</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onmouseover</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Что делать при перемещении указателя мыши над элементом </td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onmouseout</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Что делать при смещении указателя мыши с элемента</td></tr><tr><td valign="top" bgcolor="#eaeaea"><emphasis>onmouseup</emphasis></td><td valign="top" bgcolor="#eaeaea">сценарий</td><td valign="top" bgcolor="#eaeaea">Что делать при отпукании нажатой кнопки мыши </td></tr></table></p></section></section><section id="14.section.57"><section id="14.section.58"><p>В данном руководстве было показано, как создавать более строгие и четкие страницы HTML.</p><p>Главное заключается в том, что все элементы XHTML должны быть правильно вложены, документы XHTML должны быть синтаксически правильными, все имена тегов должны быть записаны в нижнем регистре, и все элементы XHTML должны быть закрыты.</p><p>Важно также то, что все документы XHTML должны иметь объявление DOCTYPE, и что должны присутствовать элементы <emphasis>html, head, title</emphasis>, и <emphasis>body</emphasis>.</p><p>Дополнительную информацию о XHTML можно найти в любом справочном руководстве по XHTML.</p></section><section id="14.section.59"><p>Следующий шаг состоит в изучении CSS и JavaScript.</p><section id="14.section.60"><p>CSS используется для управления стилем и компоновкой Web-страниц.</p><p>При использовании CSS все форматирование можно вынести из документа HTML и сохранить в отдельном файле.</p><p>CSS предоставляет полный контроль над компоновкой, не создавая путаницу в содержимом документа.</p><p>Познакомиться с каскадными таблицами стилей можно в любом руководстве по CSS.</p></section><section id="14.section.61"><p>Язык JavaScript может сделать Web-сайт более динамичным.</p><p>Статичный Web-сайт вполне подходит для вывода простого содержимого, но динамичный Web-сайт может реагировать на события и позволяет организовать взаимодействие с пользователем.</p><p>JavaScript является наиболее популярным языком сценариев в Интернет, и он работает со всеми основными браузерами.</p><p>Более подробно познакомиться с JavaScript можно с помощью любого руководства по JavaScript.</p></section></section></section></section></section><section xmlns="http://www.w3.org/TR/xhtml1/strict" id="literature"><title>Литература</title></section></body><body name="notes"><title><p>Примечания</p></title></body><binary xmlns="http://www.w3.org/TR/xhtml1/strict" content-type="image/png" id="6__6-1_gif">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
AABJRU5ErkJggg==
</binary><binary xmlns="http://www.w3.org/TR/xhtml1/strict" content-type="image/png" id="9__scope1_png">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
C2gdFWa/xHDp0xfHUxxWGJ0Yqa6tIg9dM//xi0ufvhieYgSUcnI+Kz7Tr7oPi5nDbZc+3c6eejX0
lo2QBtX8It+7TNnsr5pc+nQ7e4rxJjLPj8SwCSp5cXVXhddcbVz6dHt6ivMeEAaTSWxVrVYXW3bO
c+7vU136dLt5isHJhod4tJQMfC1b199KEcz7g12XPt0unmJw4TnC5pFiSW0jQV4nau8VeD1CNODS
py/cU4z3APPKEd+UE9R4Vg+XVzgc/hiVhkufviBPMTjGADOOF+LHJlD5ct148MkB78frYqzRp7/z
IOzBO5aptufkCdOnY3De15ntvBCSnKXms/1o9R1nGyz7XyNr9OmBAQ8DOC59OgT+aFqYpKSBgNfy
tfncvDIm0cti6ZcV+vQzUJx+3/+p1qejA9zr8LmrwSJFPjuzls++45uXJMyx7v8RrdGnwyaBm59a
fTo6wMMrhGW80eLPMghUltyPpizzsTLgBr+t0ae7X7r91OrT3XBE5lBnLBzgVHy2vph8Oo5pQ8AN
flujT7906enVp+Mo437yTGq8in1TIUq+Oiyw7q8YTYNuuT697fjtOf8//enQp3t3rqaKq4rJ9e3C
3eE2x9vot8X69Lbjn8zz/+mWsqT16ZjevLzmrO2etg/wKazQp19E5/Lvn1p9Oi6BsfB4o7j06Q7V
pxtw6dMdqk834NKnO1SfbsClT3eoPt2IS5/uQH36JC59uuP06dO49OmO0qfPxKVPd4w+3RSXPt0h
ns4x3lxaxsX31AyXPt0hnhr4P7JMY6ANMlJZAAAAJXRFWHRjcmVhdGUtZGF0ZQAyMDEwLTAzLTAy
VDE2OjQzOjE3KzAzOjAwQAiAFAAAACV0RVh0bW9kaWZ5LWRhdGUAMjAwNy0wNy0yMVQxMzo0MTow
NCswNDowMIzASvcAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAAAElFTkSu
QmCC
</binary><binary xmlns="http://www.w3.org/TR/xhtml1/strict" content-type="image/png" id="9__scope2_png">iVBORw0KGgoAAAANSUhEUgAAATwAAAC+CAMAAACf1ENTAAAABGdBTUEAAK/INwWK6QAAAwBQTFRF
////AAAA5Obu+fn7+Pj75+nw5efv4eTt4uXu+/z9+vv89vf64OLs/P399fb53+Hs/f7+8/T4/v7/
3uHr7vD16+3z6Orx3eDq6uvy7e708PH28vP3iIiIZmZmu7u7AwMDzMzMERER7u7uMzMzWVlZlpaW
REREQUFCfn+CgYKEJycn4eHhBQUGxcrkEBAQICAhDQ0NO02kIiIi3d3dzdLoqrLYMkSgTU5Ru73C
VlZWEhIS5OTksbGxycnJPz9BQkJCFSqT19jZf4CDy8zSnabSYGBii5XJsrO2VVVVkZKUgIGD1NXY
fX2BsLG02NrhkpzNCyGPfH2BwsLGmZmZfX6CrK6y2tzjGS6V2t3uAhmKm5yhcXJyoaKlsbK1d3d3
rKyxrq+zPj5AHx8gLy8wxMXLHTKWr7C0ABeJUFBSgo3F/Pz+jI2R0tPWUFFUpaWl/Pz8rq6u4OHm
fH2CwMDAiImJsbO7SUpNbG1yUVFRWFhZ1dnslJWb6urq2tzmoKCi9PX15+fnr7G5YGBg3d/lMDAx
U1NTKj2caWlp4uPnqqqq0NHUP0BBPj9B0dXqvcPgRFWpqqyxeYXB8PH4DxAQJTmabXq7b29yX2Bi
QEBC4+byk5SVMTEyyc7m7O72cX69tLS3tbzdVGOwIzeZb3By6Or03uDlJSUn9PX66uz1srnbSVmr
IiIkkpSaISEhztDUk5OTLy8xPz8/5+jqoqrUXV1dwsXMxcfPlJad7/DzkJCQo6SmXl9hbG1wXm20
j5CTLkGeESaR9/j7h5LH+/v9wMbiBhyMTl6tcXJ0UGCuaHa5YnC2ZXO4jpjLCB6NWmmz7vD3pq7W
3+Lw+fr8BRyLfYnDd4PA5efz8/T5uL7eHyAgEBAR5ebodIG/9vf7QFGnS1us3eDvDyWQWGeybm9x
BBuL+vr9s7rcoKnT4OPx9fb67/D4Pk+m4+TnYG61YmJkusDfmZqfg4SF+Pn8xcbIsLfaYWFjbW5x
T1BSn6Cjvr/El6DPlJSWICEh5+n0NkiiRleprLW2GQAAAAlwSFlzAAAASAAAAEgARslrPgAAAAl2
cEFnAAABPAAAAL4AulvyXQAADlhJREFUeNrtnQlcE9kdx+f1vtgWG2hCQgighKgkC3J4rJoFD0BQ
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
ZSBJbWFnZVJlYWR5ccllPAAAAABJRU5ErkJggg==
</binary><binary xmlns="http://www.w3.org/TR/xhtml1/strict" content-type="image/png" id="intuit_logo">iVBORw0KGgoAAAANSUhEUgAAAR0AAAA0CAMAAACAYBwDAAAABGdBTUEAALGPC/xhBQAAAAFzUkdC
AK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAwBQTFRF
////AAAA/5kAzMzMMzMz/5lm/5kz/8xmmZmZ///M/8yZZmZm/8zMAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhyw/KwAAAAlwSFlzAAAASAAAAEgARslrPgAAAAl2
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
MzgrMDQ6MDB9r915AAAAAElFTkSuQmCC
</binary></FictionBook>
