Основы программирования. Часть 2

В этой главе знакомство с основами программирования выходит на новые, интригующие горизонты. Например, будут рассмотрены вопросы принятия решений программами; вы узнаете, почему некоторые операторы сценария нужно повторять снова и снова. В самом конце главы можно будет также узнать о, пожалуй, одном из самых эффективных способов хранения информации в JavaScript: о построении массивов.

Решения и циклы

Ежедневно и ежечасно каждому из нас приходится принимать важные решения - и очень часто про это мы даже не подозреваем. Наверное, с этим согласны не все. Тогда имеет смысл рассмотреть, какие решения принимаются покупателем, скажем, в супермаркете от момента, когда он туда заходит, и до момента выхода.

Без предварительного принятия решения никто в супермаркет не заходит. В зависимости от количества и размера предполагаемых покупок, посетитель берет либо ручную сумку, либо тележку самообслуживания в углу возле стойки. Это решение позже может быть подвергнуто суровой самокритике, если по пути своего следования покупатель обнаружит скидки на товары, которых по такой цене можно было бы купить больше, да вот сумочка для ручной клади маловата. Теперь предположим, что покупатель подходит к продуктовому отделу. Прежде чем что-то выбрать, он проверяет наличие тех товаров, которые специально дома выписал на листочек, чтобы ничего не забыть. Если ассортимент покупателя устраивает, то он подойдет ближе и начнет искать нужный продукт. В противном случае покупатель пойдет к другому отделу.

Дальше предположим, что покупатель направляется к овощному разделу для того, чтобы купить спелых помидоров. Подойдя к лоту с помидорами, он начинает исследовать каждый помидор в отдельности - берет его, проверяет твердость, цвет, ищет всякие изъяны. Он забраковывает один, берет другой и долго повторяет описанные действия: до тех пор пока, наконец, не находит то, что ищет. Последней остановкой покупателя является касса. "Пакет бумажный или пластиковый?" - спрашивает продавец. Это еще одно решение, которое нужно принять. От него будет зависеть, в какой сохранности покупки будут доставлены из супермаркета прямо на кухню.

Процесс принятия решений при посещении магазина весьма напоминает то, через что проходит JavaScript при выполнении программы. Если основная идея описанного процесса уже схвачена, теперь самое время обратиться к особенностям синтаксиса JavaScript и способам реализации с его помощью программ.

Управляющие структуры

На программном языке все операторы, используемые для принятия решений, а также связанные с ними циклические команды повторения называются структурами управления (или управляющими структурами). Структуры управления, с помощью последовательности операторов сценария, направляют поток обработки данных в нужном направлении. В основе используемых методов лежит схема принятия простых решений и других факторов.

Важной частью каждой управляющей структуры является условный оператор. Точно так же, как к месту работы можно добираться несколькими путями, в зависимости от тех или иных условий (например погоды, времени суток или настроения), программа тоже иногда содержит условные выражения, которые могут принимать значения true (истина) или false (ложь)-одно из логических значений булевого типа, уже упоминавшихся в предыдущей главе 6. Как правило, в качестве подобных условных конструкций используются те, что содержат в себе оператор сравнения. В реальной жизни все происходит абсолютно аналогично: если истина заключается в том, что за окном мороз, то перед выходом на улицу лучше одеть пальто. В программировании, однако, уж если что-то сравнивают, то это, как правило, числа или строки.

Для разных программируемых ситуаций в JavaScript предусмотрены различные типы управляющих структур. Три наиболее часто используемые подобные структуры - это условный оператор if, условный оператор if... else и оператор цикла for.

Прочие управляющие структуры, о которых вам нужно иметь представление, детально описываются в последующих уроках. На данном же этапе важно освоить только упомянутые выше конструкции.

Условный оператор if

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

if (условие) {
оператор[ы], выполняемый[е], если условие справедливо }

Не стоит беспокоиться по поводу наличия фигурных скобок. Вместо этого лучше сконцентрироваться на основной структуре. Ключевое слово if является обязательным. В круглых скобках вводится выражение, значение которого имеет булев тип. Это именно то условие, которое проверяется при подходе процесса выполнения программы к данному месту. Если значение выражения равно true (истина), то будет выполнен оператор или операторы, заключенные в фигурные скобки, а после этого программа перейдет к оператору, который находится после закрывающей фигурной скобки. Если значение выражения равно false (ложь), то операторы внутри фигурных скобок игнорируются и процесс продолжается с первого оператора после закрывающей фигурной скобки.

В приведенном далее примере подразумевается, что переменная myAge имеет значение, заданное ей ранее в сценарии (как именно, в данном случае не важно). В условном выражении осуществляется проверка сравнения значения переменной myAge с числом 18.

if (myAge < 18) {
alert("Sorry, you cannot vote.") 
}

Тип данных значения myAge должен соответствовать числу, чтобы процесс сравнения (с помощью оператора сравнения <) производился корректно. Во всех случаях, когда значение myAge меньше 18, оператор в фигурных скобках будет выполнен, в результате на экране появится окно предупреждения. После того как пользователь закроет это диалоговое окно с предупреждением, выполнение сценария будет продолжено с того оператора, который расположен непосредственно после фигурной скобки, закрывающей условный оператор.

Условный оператор if...else

Не все решения в программах принимаются так просто, как это показано выше на примере условного оператора if. Вместо того чтобы определять конкретный маршрут выполнения программы только в случае выполнения или невыполнения условия, часто удобно явно указать два пути выполнения программы в зависимости от того, выполняется условие или нет. Это не очень заметное но очень важное различие. В стандартном условном операторе if в том случае, если значение контрольного выражения равно false (ложь), никакой специальный оператор не выполняется. В случае же, если и при негативном ответе при проверке условного выражения (значение false) нужно выполнить набор определенных действий, используется конструкция if... else. Синтаксис этой условной конструкции приведен ниже.

if (условие) {
оператор[ы] выполняемый[е], если условие = true } else {
оператор[ы] выполняемый[е], если условие = false }

Здесь представлено все, что уже известно о конструкции if. Главным отличием от рассмотренного выше случая является только наличие ключевого слова else. Оно введено для того, чтобы указать альтернативный путь выполнения программы в том случае, если значение проверяемого условия равно false.

Как пример использования структуры if... else приведен фрагмент кода, в котором определяется количество дней в феврале месяце в зависимости от того, високосный год или нет. Для упрощения примера в условии просто проверяется, делится ли номер года нацело на 4. (Настоящая проверка должна учитывать переход в новое столетие, но в данном случае это несущественно). Оператор в виде знака процента (%) называется модальным делением и о нем речь пойдет далее в главе 40. Результат выполнения этого оператора - это остаток от деления одного числа на другое. Если остаток равен нулю, то первое число делится на второе нацело.

var febDays
var theYear = 1993
if (theYear % 4 == 0) {
febDays =29 } else {
febDays = 28 }

Самое важное в этом примере происходит в конце кода, в конструкции if... else. Здесь значение переменной febDays устанавливается равным 28 или 29. Ни одно из других значений не является возможным. Для тех лет, числа которые нацело делятся на 4, выполняется первый встроенный оператор условной конструкции. Во всех других случаях выполняется второй оператор. Процесс выполнения кода в любом случае продолжается с первого после окончания структуры if... else оператора.

Циклы

В реальной жизни циклы означают повторение последовательности определенных шагов или действий до тех пор, пока не выполнится определенное условие. Именно это условие позволяет разорвать заколдованный круг повторений. Так было в примере с посещением магазина, когда посетитель перебирал помидоры до тех пор, пока не находил для себя подходящий экземпляр. Это же можно сказать и о блуждании вокруг квартала в поисках аптеки.

Цикл дает сценарию инструкцию периодически повторять последовательность действий до тех пор, пока не будет выполнено определенное условие. Например, программа JavaScript проверки правильности данных может анализировать каждый символ, вводимый пользователем в текстовом поле, чтобы убедиться в принадлежности его к числовым данным. Или, если у вас есть набор данных, сохраненных в виде списка, то в цикле можно проверять, где в этом списке располагается введенный символ. Как только условие выполнилось, сценарий прекращает выполнение цикла и продолжает работу со следующей после последнего оператора цикла инструкции.

Наиболее часто используемой в JavaScript циклической структурой является оператор for. Он получил свое название по первому слову используемого в нем оператора. Оператор цикла for является мощным программным средством, поскольку с его помощью можно много раз подряд выполнять самые сложные операторы. Используется этот оператор следующим образом.

for ([начальное выражение]; [условие]; [выражение обновления]) {
операторы внутри цикла }

Квадратные скобки указывают на то, что расположенные в них параметры, не обязательные для введения. Тем не менее, пока у вас нет твердых навыков использования оператора цикла for, хотелось бы порекомендовать использовать эти опции в каждом случае. Раздел начальное выражение обычно используется для того, чтобы установить начальное значение для счетчика цикла. Под условием подразумевается такое же выражение, что использовалось в условной конструкции if. В данном случае это выражение определяет условие, при наступлении которого выполнение цикла прекращается. Наконец, выражение обновления представляет собой оператор, который выполняется каждый раз после выполнения всех вставленных в тело цикла операторов.

Общий принцип использования цикла подразумевает инициализацию переменной i, значение которой постоянно увеличивается по ходу выполнения цикла. Так продолжается до тех пор, пока это значение не превысит некоторой максимальной величины, как это показано в следующем примере.

for (var i = startValue; i <= maxValue; i++) {
операторы цикла 
}

Под startValue и maxValue в данном случае подразумевается произвольное числовое значение, включая заданные явно числа или переменные с числовыми значениями. В выражении обновления использован оператор, с которым до этого сталкиваться не приходилось. Оператор ++ увеличивает значение i на 1 каждый раз после выполнения тела цикла. Это увеличение происходит обязательно после выполнения итерации цикла. Если значение startValue равно 1, то в первой итерации цикла значение i будет равно 1, во второй итерации- 2 и так далее. Затем, если значение maxValue равно 10, то цикл будет повторен ровно 10 раз (другими словами, до тех пор, пока значение i будет меньше либо равно 10). Вообще говоря, выражения в теле цикла могут также использовать значение переменной-счетчика. Позже в этой главе будет показано, как переменная играет ключевую роль в операторах тела цикла. В то же самое время, очень важно знать, как преждевременно прервать выполнение цикла и, особенно, в каких ситуациях подобное прерывание может понадобиться.

Функции

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

Тем, кто уже имеет опыт программирования, может показаться очевидным подобие функций JavaScript и подпрограмм в других средах программирования. Но, в отличие от других языков, где используется разделение на процедуры (в которых выполняются последовательности действий) и функции (в которых выполняются действия и в качестве результата обязательно возвращается значение), в JavaScript подобного разделения нет. Функция в JavaScript может возвращать значение в вызывающий ее оператор, однако это требование не является обязательным. Тем не менее, когда при использовании функции значение все же возвращается, вызывающий ее оператор трактует эту функцию как обычное выражение - значение функции используется именно в том месте, откуда эта функция вызвана.

Формальный синтаксис использования функций выглядит так:

function имяФукции([параметр] или [параметры]) {
операторы 
}

На имена, которые присваиваются функциям, накладываются те же ограничения, что и на названия элементов и переменных HTML. Можно порекомендовать использовать такое название для функции, которое отображало бы задачи, возлагаемые на нее. Удобным при этом является использование названий из нескольких слов в слитном формате. В этом случае название лучше начинать с глагола, поскольку функция выполняет действие, даже если все, что она делает, - это получает или устанавливает значение определенной переменной.

Очень полезно при написании функций задавать ей узкую специализацию. В принципе, можно сгенерировать функцию длиной в несколько сотен строк кода. Однако такие функции трудно обслуживать и отлаживать. Поэтому такие громадные конструкции лучше разбивать на небольшие, на более сегментированные структуры.

Параметры функций

Приведу пример обработчика события, который вызывает функцию с помощью ее названия. Любой вызов функции, включая и функции из других операторов JavaScript, осуществляется по одной и той же схеме: в конце названия каждой функции следуют скобки.

Можно определить функцию так, что она будет получать значения своих параметров непосредственно из вызывающего ее оператора. В листинге показан пример документа, в который добавлена кнопка. Обработчик события onClick этой кнопки вызывает функцию, передавая ей при этом текстовые данные в качестве параметра. Текстовая строка, используемая в вызове обработчиком события, является вложенной строкой - это набор одинарных кавычек внутри двойных кавычек, используемых во внешних атрибутах обработчика событий.

Листинг. Вызов функции обработчиком события

<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
function showMsg(msg) {
alert(msg)
}
</SCRIPT>
</HEAD>
<BODY>
<FORM>
<INPUT TYPE="button" VALUE="Нажми!" 
onClick="showMsg ('Ты нажал меня!')">
</FORM>
</BODY>
</HTML>

Параметры (известные также как аргументы) призваны обеспечить механизм "передачи" значения от одного оператора к другому в процессе вызова и выполнения функции. Если в определении функции не используется вообще никаких параметров, то и в описании функции при ее вызове используется пустая пара скобок.

Переменным, указанным на месте параметров в описании функции, присваиваются вводимые в коде вызова функции значения. Рассмотрим, например, такой фрагмент кода сценария:

function sayHiToFirst(a,b,с) (
alert("Say hello, " + a) )
sayHiToFirst("Gracia", "George", "Harry")
sayHiToFirst("Larry", "Мое", "Curly")

После того как функция определена в сценарии, в следующем операторе эта же функция и вызывается. Ей в качестве параметров при этом передается три строки. В силу определения функции значения строк присваиваются параметрам а, Ь и с. Поэтому еще до того, как будет выполнено оператор alert () внутри функции, значение а будет приравнено "Gracia", значение b- "George", а значение с- "Harry". Поскольку в операторе alert () используется только значение а, то в результате получаем сообщение

Say hello, Gracia

После того как пользователь закроет окно первого сообщения, согласно сценарию данная функция будет вызвана еще раз. На этот раз, тем не менее, функции передаются уже другие значения, которые и будут присвоены параметрам а, Ь и с. Диалоговое окно в этом случае содержит такое предупреждение:

Say hello, Larry

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

Диапазон действия переменных

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

Глобальные переменные в JavaScript имеют совершенно иное, особое значение, по сравнению с большинством других языков. Для JavaScript пределы "глобальности" для переменных простираются до размеров текущего документа, загруженного в окно браузера. Поэтому инициализация переменной в качестве глобальной подразумевает, что все операторы страницы (включая и те, что расположены в описании функций) получают прямой доступ к значению этой переменной. Операторы могут восстанавливать и изменять значения глобальных переменных в любом месте страницы. Используя терминологию программирования, можно сказать, что эти переменные имеют глобальную область действия, поскольку буквально все элементы страницы могут их использовать для своих нужд.

Помните, что в тот самый момент, когда страница выгружается, все глобальные переменные, определенные на ней, будут удалены из памяти. Если нужно передать какое-то значение от одной страницы к другой, то для этого следует использовать другие технологии (их я опишу позже). В то время как ключевое слово var при инициализации глобальных переменных обычно задавать необязательно, я бы настоятельно порекомендовал использовать его в любых ситуациях. Это поможет избежать недоразумений при работе с будущими версиями языка JavaScript.

В отличие от глобальных переменных, локальные переменные определяются внутри функций. С тем, как в функциях описываются параметры вам уже приходилось сталкиваться (в этом случае ключевое слово var при инициализации не использовалось). Что касается остальных переменных, то их можно определить с помощью ключевого слова var (для локальных переменных его использовать обязательно всегда). Диапазон легитимности локальных переменных не выходит за рамки операторов в теле описания функции. Ни одна другая функция или оператор вне текущей не в силах получить доступ к локальной переменной.

"Локальная область действия" определяется в тех случаях, когда для разных локальных переменных в рамках одного документа используются одинаковые названия. В большинстве случаев подобная практика весьма ущербна, поскольку приводит к очень неприятным ошибкам, которые крайне тяжело отслеживать. В то же время, в некоторых случаях удобно использовать одни и те же названия, скажем, для счетчиков в программном цикле for. Это вполне безопасно, поскольку такие счетчики в начале запуска цикла каждый раз заново инициализируются с начальным значением. Тем не менее, вставить один цикл for в другой такой же цикл, не использовав при этом отличную переменную для счетчика, вам не удастся.

Для того чтобы продемонстрировать структуру и поведение локальных и глобальных переменных, а также показать, почему крайне нежелательно использовать в документе для разных переменных одинаковые названия, ниже приведен листинг. В нем описаны две локальные и две глобальные переменные. При этом названия локальной переменной из методологических соображений взято таким, что совпадает с названием глобальной переменной.

Листинг. Демонстрация использования локальных и глобальных переменных.

<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript'^
var aBoy = "Charlie Brown"   // глобальная переменная
var hisDog = "Snoopy"        // глобальная переменная
function demo() {
// Это пример того, как поступать не следует 
var hisDog ="Gromit"
// локальная версия переменной hisDog 
var output = hisDog + "does not belong to "+ 
aBoy + "<BR>" +document.write(output)
}
</SCRIPT>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
// запускается при загрузке документа
demo()
document.write(hisDog + "belongs to " + aBoy + ".")
</SCRIPT>
</BODY>
</HTML>

Когда страница загружается, сценарий в разделе заголовка инициализирует две глобальные переменные (aBoy и hisDog) и создает в памяти функцию demo(). В теле документа другой фрагмент сценария вызывает эту функцию. Внутри функции инициализируются две локальные переменные, одна из которых (hisDog) имеет название, совпадающее с названием глобальной переменной. В JavaScript такое двойное описание переменной приводит к тому, что везде в пределах данной функции приоритетным для всех операторов функции будет описание локальной переменной. Однако следует обратить внимание на тот факт, что если убрать ключевое слово var из локальной инициализации, то в результате глобальной версии этой переменной будет присвоено новое значение "Gromit".

Другая локальная переменная output предназначена скорее для сохранения текста, чем для отображения его на экране. Аккумуляция текста переменной начинается с того момента, когда вычисляется значение локальной переменной hisDog. Затем проводится объединение текстовых фраз (обратить внимание на дополнительные пробелы в конце строк). Затем определяется значение глобальной переменной aBoy. Ни одна глобальная переменная не может быть вытеснена локальной переменной, доступной в данной функции. После этого определяется выражение HTML, которое нужно отобразить на странице так, чтобы оно заканчивалось пробелом и дескриптором <BR>. В последнем операторе функции содержимое выводится на странице.

После того как стоящая перед функцией задача выполнена, следующий оператор тела документа выводит на страницу еще одну строку. Поскольку этот оператор сценария реализуется в глобальной области действия (т.е. он находится вне функции), то в таком представлении ему будут доступны только глобальные переменные, включая и те, что определены внутри других дескрипторов <SCRIPT> данного документа. К тому моменту, когда загрузка всей страницы полностью завершена, на странице будет отображаться следующий текст:

Gromit does not belong to Charlie Brown. Snoopy belongs to Charlie Brown.

Использование фигурных скобок

Несмотря на тот факт, что многим иногда - а, может, еще и ни разу -приходилось использовать фигурные скобки ( {} ), нет ничего мистического в том, как они задаются в JavaScript (и многих других языках). Фигурные скобки используются для выделения блоков кода, которые должны выполняться вместе. Кроме того, что наличие таких фигурных скобок позволяет программистам легче разбираться в последовательности выполнения операторов, так они еще помогают броузеру определить порядок группировки инструкций. Фигурные скобки вводятся только парами.

Фигурные скобки используются в основном в описаниях функций и в управляющих структурах. В описании функции в листинге 2 фигурные скобки группируют вместе четыре оператора, которые выполняют все ее действия (включая и строки комментария). Закрывающая скобка дает знать броузеру, что все, что расположено после нее, к функции никакого отношения не имеет.

Что до синтаксического размещения фигурных скобок, то жестких правил в JavaScript на этот счет не существует (как в этом уже можно было убедиться). Приведенные ниже описания функций трактуются броузером совершенно идентично:

function sayHiToFirst(a, b, с) {
alert("Say hello, "+a) }

function sayHiToFirst(a, b, c) 
{
alert("Say hello, "+a)
}

function sayHiToFirst(a, b, c) {alert("Say hello, "+a)}

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

Массивы

В JavaScript одним из наиболее полезных способов организации и хранения данных являются массивы. Представить себе самый простой массив можно в виде одномерной таблицы. В каждом столбце строки такой таблицы содержатся данные, при этом каждый столбец пронумерован. Для нумерации столбцов массива используется строгая числовая последовательность, а первый столбец имеет нулевой номер (программисты всегда начинают считать с нуля). Эти номера столбцов массива еще называют индексами. Для получения доступа к элементу массива, нужно знать название этого массива и номер столбца нужного элемента массива. Поскольку значения индексов начинаются с нуля, то общее количество элементов массива (определяется свойством массива length) всегда на единицу больше самого большого индекса в массиве. Более продвинутая концепция массивов позволяет создавать подобие массива с несколькими строками в столбце. Такие структуры опишу позже. На данном этапе имеет смысл ограничиться рассмотрением массивов, состоящих из одной строки.

Данные, хранящиеся в качестве элементов массива в JavaScript, могут быть любого типа, в том числе и объектами. И, в отличие от большинства других языков программирования, в различных столбцах массива JavaScript могут содержаться данные разных типов.

Создание массива

Массив определяется с помощью переменной. Поэтому при создании массива переменной присваивается объект нового массива. Да, массивы являются объектами JavaScript, но к базовому языку JavaScript они все же имеют большее отношение, чем к объектной модели документа. При объявлении массива используется специальное ключевое слово new. Это делается для того, чтобы вызвать специальную функцию JavaScript, которая сгенерирует массив и выделит для него место в памяти. Необязательный параметр функции Array() позволяет указать еще во время создания массива, сколько ориентировочно элементов зарезервировано в данном массиве. В этом смысле JavaScript является очень демократичным языком, поскольку размер массива можно изменять в любое время. Поэтому, если при создании нового массива в качестве параметра ничего указано не будет, то сценарий от этого совершенно не пострадает.

Для того чтобы наглядно продемонстрировать процесс создания массива, ниже приведен код конструктора массива, элементами которого являются названия 50 штатов и одного округа Колумбия (всего 51 элемент). Первым делом создается массив и ему присваивается имя, которое лучше всего характеризует данные, содержащиеся в нем.

var USStates = new Array(51)

Начиная с этого момента в памяти выделено место для массива с названием USStates, содержащего 51 элемент. Для того чтобы заполнить этот массив, каждому его элементу нужно присвоить значение. Обращение к каждому элементу массива требует использования специального индекса: сначала указывают название массива, а затем в квадратных скобках вводится индекс нужного элемента. Первым элементом в массиве USStates будет USStates[0]

Чтобы присвоить первому элементу массива первое по алфавиту название штата, необходимо воспользоваться обычным оператором присваивания

USStates[0] = "Alabama"

Остальные элементы массива можно заполнить следующим способом:

USStates[1] = "Alaska"
USStates[2] = "Arizona"
USStates[3] = "Arkansas" 
***
USStates[50] = "Wyoming"

Поэтому, если в документе нужно использовать таблицу данных, из которой сценарий впоследствии должен получать информацию, то для исключения обращения к серверу, можно оформить ее в виде массива. Если сделать соответствующие операторы выполняющимися в процессе загрузки документа, то к тому моменту, когда документ будет полностью отображен в броузере, массив данных уже будет создан и готов к использованию. Несмотря на то, что у вас может сложиться впечатление о необходимости использования в такой ситуации большого числа операторов, объем загружаемых данных, на самом деле, достаточно невелик и не представляет особых проблем, потому загрузка страницы проходит идеально даже у тех пользователей, кто использует каналы соединений со скоростью передачи данных 28,8 Кбит/с.

Получение доступа к данным массива

Индекс элемента массива является тем ключом, который позволяет получать доступ к нему. Указав название массива и индекс нужного элемента в квадратных скобках после названия, можно получить значение, записанное в соответствующем столбце массива. Например, после того как массив USStates создан, сценарий может вывести на экран окно сообщения с названием штата Аляска, для чего предназначается следующий код:

alert("The largest state is " + USStates[1] + ".")

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

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

Параллельные массивы

Ниже показано, почему использование в качестве индексов массивов чисел в JavaScript является оптимальным вариантом. Для того чтобы пример был более наглядным, нужно сгенерировать еще один массив наряду с уже существующим USStates. Этот новый массив также будет состоять из 51 элемента и содержать в качестве данных годы, в которые соответствующие штаты из первого массива USStates вступили в Конфедерацию. Выглядит описанная выше структура следующим образом:

var stateEntered = new Array(51)
stateEntered [0] = 1819 
stateEntered [1] = 1959 
stateEntered [2] = 1912 
stateEntered [3] = 1836
***
stateEntered [50]   1890

Содержащиеся в памяти броузера две таблицы с данными можно представить так, как показано на рис.1. Сюда же можно, используя описанный принцип, добавить любое число дополнительных массивов, параллельные данным. Например, это могут быть почтовые индексы или названия столиц штатов. Важно отметить, что нулевые элементы всех массивов соответствуют штату Алабама, первому штату массива USStates.

Если на Web-странице используются обе эти таблицы, и пользователю необходимо произвести поиск даты вступления конкретного штата в Конфедерацию, то сначала придется просмотреть все записи массива USStates, найти индекс нужного штата, а затем по данному индексу из массива stateEntered можно узнать нужную дату.

Рис.1. Вид двух реляционных таблиц
 "Alabama"
 "Alaska"
 "Arizona"
 "Arcansas"
 ***
 "Wyoming"
[0]
[1]
[2]
[3]
[***]
[50]
 1819
 1959
 1912
 1836
 ***
 1890

В данном примере на страницу добавляется текстовое поле, куда пользователь может вводить название штата, дата вступления которого в Конфедерацию подлежит поиску. В реальном приложении такой подход чреват всевозможными "подвохами". В том числе следует обязательно проверять правильность вводимого пользователем названия.

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

function getStateDate() {
var selectedState=document.entryForm.entry.value 
for (var i = 0; i<USStates.length; i++) {
if (USStates [i] == selectedState) {
break }
}
alert("The state entered the Union in "+
stateEntered[i]+".") 
}

В первом операторе функции переменной selectedState присваивается то значение, которое введено пользователем в текстовом поле. Такое длинное название для переменной выбрано скорее из соображений наглядности, чем удобства. Фактически, эта переменная используется только в цикле for, так что броузеру не нужно каждый раз преобразовывать длиннющую ссылку на текстовое поле, что в конечном счете способствует повышению эффективности сценария.

Основная изюминка функции спрятана именно в цикле for. Как раз здесь объединены процесс увеличения счетчика на каждом этапе выполнения цикла с использованием этого счетчика в качестве индекса для элементов обоих массивов. В параметрах цикла указано, что начальным значением для переменной-счетчика i должен быть нуль. Цикл будет выполняться до тех пор, пока значение переменной i будет меньше длины массива USStates. He забывайте, что длина массива всегда на единицу больше, чем индекс последнего элемента в этом массиве. Поэтому, когда цикл будет запускаться последний раз и значение переменной i будет равно 50, что точно меньше длины массива, равной 51, то это будет соответствовать индексу последнего элемента массива. Каждый раз после выполнения очередной итерации значение переменной-счетчика будет увеличиваться на единицу.

Внутри оператора цикла for используется условный оператор if, с помощью которого проверяется совпадение значения элемента массива с тем, что введено пользователем в текстовом поле. Каждый раз при запуске цикла условие проверяется для очередного элемента массива, начиная с элемента с индексом нуль. Другими словами, условие, использованное в операторе if, может проверяться десятки раз, пока совпадение не будет обнаружено. Но каждый раз при этом значение переменной i увеличивается на единицу по сравнению с предыдущим вариантом.

Оператор проверки равенства (==) чрезвычайно пунктуален, когда ему приходится сравнивать строковые значения. В этом случае на совпадение проверяются символы с учетом регистра (т.е. строчные и прописные буквы различаются). В данном примере для того чтобы совпадение вообще было обнаружено, название штата должно указываться пользователем абсолютно идентично тому, как оно представлено в массиве USStates.

Если совпадение названий обнаружено, выполняется оператор, заданный внутри условного оператора if. Оператор break добавлен в сценарий на тот случай, если понадобится прервать выполнение программы. В данном приложении при обнаружении совпадения оператор цикла for досрочно прекращает работу. Когда цикл for прерывается, значение переменной i фиксируется на том значении, которое соответствует элементу массива USStates, в котором хранится нужная запись. Это значение впоследствии используется для получения доступа к элементу другого массива. Даже несмотря на то, что переменная-счетчик i специально инициализирована для использования в операторе цикла for, она остается доступной в пределах функции для всех операторов даже после выполнения цикла. Вот почему эту переменную можно использовать для того, чтобы определить значение нужного элемента в массиве stateEntered и отобразить результат в окне сообщения.

Приведенный пример использования в операторе for переменной-счетчика для указания индексов является довольно типичным для JavaScript. Поэтому внимательно изучите код и разберитесь, как он работает. Это имеет отношение не только к способам управления массивами, но и к генерации броузерами массивов в объектных моделях документов.

Объекты документа в массиве

Если заглянуть вперёд, то нетрудно заметить, что свойства некоторых объектов приводятся с помощью квадратных скобок после соответствующих названий. Это, в самом деле, такие же самые квадратные скобки, которые использовались выше для указания элементов массива. Так происходит потому, что при загрузке документа броузером в документе создаются объекты, подобные массивам. Например, если на странице используются два дескриптора формы <FORM>, то в документе появится две формы. В броузере будет поддерживаться массив объектов форм для данного документа. Ссылаться на такие формы можно следующим образом:

document.forms[0]
document.forms[1]

Индекс значения для объектов документа присваивается в зависимости от очередности загрузки объектов. В случае с объектами формы, такой порядок определяется очередностью следования дескрипторов формы <FORM> в коде документа. Такая индексная форма записи является еще одним способом представления формы в структуре ссылки на объекты. Параллельно можно продолжать использовать названия форм, что намного удобнее, поскольку в последнем случае изменение порядка их следования в коде HTML-документа никак не повлияет на ссылки. Но если страница содержит, скажем, только одну форму, то можно использовать разные типы ссылок поочередно, как это показано на примере обращения к свойству value текстового поля формы.

document.entryForm.entry.value
document.forms[0].entry.value

В многочисленных примерах скриптов можно найти ссылки самых разных типов и структур. Однако подобное разнообразие редко применяется одновременно в серьезных программных разработках.

Упражнения к уроку
Hosted by uCoz