- Java script -
Java - это один из самых исполбзуемых языков HTML.
Им можно составить графические и разные другие проги.
Этот текст предназначен тем, кто начинает
изучать JavaScript. В изучении любого языка
программирования есть несколько путей:
- изучить формальное описание языка, а затем - способы его применения
для решения конкретных задач.
- изучить способы применения языка для решения конкретных задач
  и на примере этих задач изучить необходимые черты
  и особенности ("подмножество") языка программирования.
   
  JavaScript - несколько необычный язык программирования, поскольку
  предназначен для управления конкретным объектом - бродилкой.
Поэтому я избрал смешанный способ изложения сведений о языке - на примере конкретной задачи ('Игра в "15"') и нескольких более простых задач читатель, с одной стороны, познакомится со средствами JavaScript, позволяющими решать сходные задачи, а с другой стороны, усвоит значительную часть формализма JavaScript (надеюсь, достаточную, чтобы самостоятельно продолжить изучение этого языка, используя существующие учебники, учебные тексты, доступные в Интернет, и программы других авторов).

Этот текст не представляет из себя полного учебника по JavaScript. В нем освещаются лишь несколько тем, в частности, полностью опущена работа с кадрами и формами (пока).

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

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


Содержание

1. Что это такое?
2. Для чего?
3. Ввод и вывод
4. Где и в каком виде хранятся программы JavaScript?
4.1. Запись программы JavaScript в HTML-странице
5. Элементы языка - от программы к программе.
5.1. Комментарии JavaScript
5.2. Вывод текста в модальное окно
5.2.1. Отступление: литеральные строки
5.3. Переменные
5.4. Простейшие операции
5.4.1. Присваивание
5.4.2. Арифметические операции
5.4.2.1. Сложение, вычитание, умножение, деление
5.4.2.2. Добавление единицы (автоинкремент и автодекремент)
5.4.3. Конкатенация (сцепление) строк.
5.5. Объекты бродилки
5.5.1. Окно как объект Window
5.5.1.1. Открытие окна с непосредственной загрузкой документа во вновь открываемое окно
5.5.1.2. Открытие окна с последующей загрузкой документа в него
5.5.1.3. Открытие окна по запросу
5.5.2. Документ как объект document
5.5.3. Изображение как объект Image
5.5.3.1. Формальный подход
5.5.3.2. Временной фактор
5.5.3.3. Именованные изображения
5.5.4. Введение в формы: кнопка и нажатие на нее (onClick)
5.5.4.1. Форма с кнопкой
5.5.4.2. Простейшая реакция на событие
5.5.4.3. Пишем функцию для обработки события
5.5.4.4. Обработка событий - функция с параметрами
5.5.5.5. Закрыть окно!
5.6. Вычисляемое значение атрибута ярлыка HTML
5.7. Условный оператор
5.8. Программа в одном окне - действие в другом
5.9. Ссылка на функцию JavaScript в элементе <A>
5.10. Случайные числа. Объект Math
6. Собираем все вместе
7. Заключение


1. Что это такое?

JavaScript - язык программирования. Он содержит все элементы, которые присущи языкам программирования - переменные, циклы, условные операторы.

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


2. Для чего?

Для чего еще один язык программирования?

JavaScript имеет два предназначения: для работы под управлением Web-сервера и для управления компонентами бродилки (броузера). Поэтому существует 2 диалекта JavaScript. Конечно, эти диалекты имеют общую часть (зафиксированную в международном стандарте ECMA-266).

Мы изучаем только диалект JavaScript, предназначенный для управления бродилкой, и далее, говоря "JavaScript", будем иметь ввиду только этот его диалект.

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

Ограничения JavaScript выражаются прежде всего в ограничениях на источники ввода данных и пути их вывода, доступные программам на JavaScript.


3. Ввод и вывод

Откуда программа на JavaScript берет данные и куда она выводит результаты своей работы?

Как правило, JavaScript берет данные из HTML-страницы, но в нем есть нечасто используемая возможность задать вопрос пользователю и прочитать ответ (т.е. присвоить некоторой переменной значение, равное строке, которую ввел в ответ пользователь).

Программа JavaScript не в состоянии прочитать (т.е. запомнить в некоторой переменной) всю HTML-страницу - он может прочитать значения лишь нескольких ее составляющих - кадров (frames), слоев (layers - HTML 4), ссылок, форм и изображений. Структура и оформление готовой HTML-страницы остаются "недоступными для понимания" JavaScript.

Но программа JavaScript может вывести HTML-текст (созданный ею же самой!) в какое-то окно бродилки (например, в кадр). Она может также:

И больше почти ничего JavaScript не может - не для того предназначен.


4. Где и в каком виде хранятся программы JavaScript?

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

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

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

Кроме того, написание текста JavaScript-программы непосредственно в HTML-документе требует определенных действий по скрытию этого текста с тем, чтобы он не появился в окне бродилки - мы ведь пишем программу не для того, чтобы ее читали (по крайней мере не только для того), но для того, чтобы с ее помощью выполнять определенные действия.


4.1. Запись программы JavaScript в HTML-странице

Программы JavaScript можно записывать в любом месте HTML-страницы. В некоторых случаях целесообразно записать одну часть программы в одном месте (например, в заголовке - элементе <HEAD>), а другую - в другом (например, в конце HTML-страницы после тела документа - элемента <BODY> или в значении атрибута формы или еще где нибудь). В любом случае текст фрагмента программы заключается в элемент-контейнер <SCRIPT>:
<SCRIPT LANGUAGE="JavaScript">

  Здесь пишется текст программы

</SCRIPT>
В соответствии со стандартом HTML, ярлыки <SCRIPT LANGUAGE="JavaScript"> и </SCRIPT>, как не принадлежащие к HTML, игнорируются, но текст между этими ярлыками остается виден. Чтобы его скрыть, необходимо заключить этот текст в контейнер - комментарий HTML:
<SCRIPT LANGUAGE="JavaScript">
<!--

  Здесь пишется текст программы


-->
</SCRIPT>
JavaScript понимает и игнорирует первую строку контейнера <SCRIPT> (начинающую комментарий HTML). Ему (языку JavaScript) легко это сделать, поскольку никакая строка никакой програмы JavaScript не может начинаться со знака "<". Но JavaScript не в состоянии отличить последнюю строчку контейнера (в том виде, в котором мы только что ее написали) от [ошибочного] оператора, начинающегося с двойного минуса - такой оператор ЕСТЬ в JavaScript. Поэтому необходимо эту последнюю строку контейнера записать в виде комментария JavaScript:
<SCRIPT LANGUAGE="JavaScript">
<!--

  Здесь пишется текст программы

//-->
</SCRIPT>
Таким образом, мы только что изучили первый оператор JavaScript - однострочный комментарий.

Как правило, мы будем записывать программы JavaScript в заголовке HTML-страницы. Это обеспечивает загрузку наших программ ДО ТОГО, как пользователь начнет с ними взаимодействовать. Все отступления от этого правила я буду комментировать, объясняя, почему в том или ином конкретном случае следует записать конкретный кусок программы в конкретном месте.


5. Элементы языка - от программы к программе.



5.1. Комментарии JavaScript

Комментарии JavaScript бывают однострочные и многострочные. С однострочными мы только что познакомились:
<SCRIPT LANGUAGE="JavaScript">
<!--

// Это однострочный комментарий

  // Это еще один - эта программа состоит из трех комментариев

// А это еще один - эта программа ничего не делает

//-->
</SCRIPT>
Знак "//" может стоять и не в начале строки - в начале строки может быть написано что-нибудь полезное с точки зрения JavaScript. Однострочный комментарий начинается с "//" ("двух косых") и заканчивается в конце той же строки - бродилка игнорирует остаток строки от двух косых до еонца той же строки.

Когда необходимо написать большой комментарий, состоящий из нескольких строк, используются обозначения многострочного комментария:
<SCRIPT LANGUAGE="JavaScript">
<!--

/* - начало многострочного комментария

   Это уже многострочный комментарий
   - эта программа состоит из единственного комментария
   и ничего не делает

конец многострочного комментария - */

//-->

</SCRIPT>
Многострочный комментарий начинается с последовательности символов "/*" и заканчивается теми же символами, написанными в обратном порядке: "*/". Бродилка игнорирует эти комбинации символов и все, что написано между ними. Эти комбинации символов могут находиться в любом месте строки, и часто употребляются для того, чтобы временно исключить часть написанного вами кода (а через некоторое время включить обратно, убрав знаки комментария).

Пишите комментарии! Через неделю вы можете забыть, что вы имели ввиду, когда писали пару строк в середине программы (а через пару недель - забудете наверняка ;-). Поэтому комментируйте свои намерения. Конечно, ваши комментарии будут передаваться через Интернет вместе с той HTML-страницей, в которой содержится написанный вами JavaScript-текст, и, возможно, кто-то прочтет ваши комментарии. Если вы этого не хотите, перед загрузкой страницы на сервер комментарии можно удалить.

Говорят, что бродилки не в состоянии переварить комментарии, написанные на русском языке - от некоторрых комбинаций символов у них начинаются ошибки. Если вы можете, пишите комментарии по-английски. Впрочем, я не наблюдал девиантного поведения Netscape Communicator 4.04 и 4.05, с которыми я работаю, от русских комментариев.


5.2. Вывод текста в модальное окно

Страница с приведенной ниже программой содержится в файле 1.htm.
<SCRIPT LANGUAGE="JavaScript">
<!--

alert("Перва\я программа");
-->
</SCRIPT>
Эта программа выводит модальное окно (т.е. такое, которое невозможно закрыть, не выполнив требуемые в нем действия, в данном случае - не нажав кнопку "OK"):

Обратим внимание на несколько моментов в нашей программе, состоящей всего лишь из одной строки:

  1. Действие, которое выполнила наша программа - вывод модального окна - произошло в результате выполнения функции alert().

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

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

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

  2. Этой функции мы передали аргумент - строку "Перва\я программа".

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

    В нашем случае список аргументов состоял из единственной строки - "Перва\я программа". Скоро мы научимся задавать списки, состоящие более чем из одного аргумента, пустые списки аргументов (попробуйте сами!) и аргументы, не являющиеся строками (а что, если написать alert(125); ? - попробуйте!).

5.2.1. Отступление: литеральные строки

  1. Строка, которую мы хотим вывести, заключена в двойные кавычки.

    Все строки, которые следует понимать дословно (т.н. литеральные строки или, короче, литералы), а не как операции JavaScript, следует заключать в кавычки - двойные или простые - можно было бы написать и 'Перва\я программа'. Если необходимо использовать кавычки внутри строки, то следует строку заключать в противоположные кавычки: "Windows'98" и 'бродилка "Навигатор"'. А уж если необходимо использовать и те, и другие, то следует воспользоваться обратной косой чертой. Обратная косая черта, поставленная перед любым символом в литеральной строке, изменяет значение этого символа для JavaScript (в том числе лишая кавычки своего магического свойства заканчивать литеральные строки: "Кто же знает, как будет работать бродилка \"Навигатор\" в Windows\'98?". Важным применением обратной косой черты в литеральных строках является символ перевода строки "\n" (от английского New Line - новая строка): alert("Кто же знает, как будет работать\nбродилка \"Навигатор\" в Windows\'98?") выведет модальное окно с сообщением в две строки (попробуйте!).

  2. Перед строчной русской буквой "я" стоит обратная косая черта.

    Строчная русская буква "я" в кодировке Windows-1251 имеет код 255 - последний в кодовой таблице. По видимому, JavaScript использует этот код для своих внутренних целей, и поэтому нужно лишить букву "я" в литеральной строке этого ненужного нам свойства, применив обратную косую черту.

  3. Единственная строка нашей программы заканчивается точкой с запятой.

    Программа JavaScript состоит из операторов. Признаком конца оператора служит точка с запятой. (Строго говоря, не всегда - иногда операторы оканчиваются и без точки с запятой, а иногда точка с запятой встречается в середине оператора. Все особые случаи мы обсудим по ходу дела.) В нашей программе - единственный оператор, называемый оператором вызова функции.
Вывод текста в модальное окно часто используется для диагностического сообщения, которое вставляется в программу в процессе ее отладки, а затем удаляется (или комментируется). Попробуйте выполнить следующую программу:
<SCRIPT LANGUAGE="JavaScript">
<!--

// Проверим, работает ли арифметика:
alert(2+2);

-->
</SCRIPT>


5.3. Переменные

Строки, числа и другие объекты JavaScript можно хранить в переменных. Объекты JavaScript приходится хранить в переменных, если есть необходимость манипулировать ими - "склеивать" строки, складывать числа и т.д.
Переменная -
это пара: имя и значение

Переменная задается оператором определения переменной, начинающимся с ключевого слова var, за которым через пробел следует имя переменной:
var a;
var __some_strange_name__;
var MoyaNovayaPeremennaya_1;

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

Заглавные и строчные буквы в именах переменных JavaScript различаются:
var a;
var A;
// Определены две разные переменные.
В JavaScript есть довольно много зарезервированных слов (это имена всех встроенных объектов JavaScript и всех встроенных функций, поскольку функции JavaScript - это тоже объекты). Такие имена НЕЛЬЗЯ давать вашим собственным переменным. С одним из них вы уже знакомы - это alert. Относительно полный список зарезервированных слов JavaScript можно найти в книге: С.Спейнаур, В.Куэрсиа. Справочник Web-мастера. Пер. с англ.-К.:Изд. группа BHV, 1997.-ISBN 5-7733-0031-1.


5.4. Простейшие операции

5.4.1. Присваивание

До сих пор мы были в состоянии лишь дать имя переменной. Но переменная состоит из имени и значения. Присвоить значение переменной можно с помощью операции присваивания:
var a;
a=1;

var myString;
myString="Мо\я строка";

a=myString;
В первых двух строках я определил переменную a и присвоил ей значение 1. В следующих двух строках создана переменная myString и ей присвоено значение "Мо\я строка". В последней строке переменной a присваивается значение, которое имеет другая переменная - myString, т.е. теперь и она имеет в качестве значения строку "Мо\я строка". JavaScript безразлично, что хранит переменная - число, строку или какой-либо иной объект. В любом месте программы вы можете поместить в переменную все, что пожелаете.

Как проверить, что написанная выше программа делает именно то, что я сказал? Очень просто: вставить в нее несколько вызовов функции alert() (см. 2.htm):
<SCRIPT LANGUAGE="JavaScript">
<!--

var a;
a=1;
// Сейчас будет 1
alert(a);

var myString;
myString="Мо\я строка";

a=myString;
// А сейчас будет "Моя строка"
alert(a);

-->
</SCRIPT>

Определения переменных и присваивание им начальных значений можно объединять:
var a=1;
var myString="Мо\я строка";
Как правило, полезно давать переменным начальные значения - потом легко можно будет проверить, что происходит!

5.4.2. Арифметические операции

5.4.2.1. Сложение, вычитание, умножение, деление
С переменными, содержащими числовые значения, можно выполнять арифметические операции:

Основные арифметические операции JavaScript
Операция Знак
   Сложение +
   Вычитание -
   Умножение *
   Деление /

Результат выполнения арифметических (и других!) операций можно запомнить в переменной (присвоить ее значению результат выполнения операции):
var FondZarplaty=1;
var Nachisl=0.385;
var FZP_i_Nachisl;

FZP_i_Nachisl=FondZarplaty*(1+Nachisl);

5.4.2.2. Добавление единицы (автоинкремент и автодекремент)
Часто возникает необходимость добавить к значению какой-то переменной единицу. Для этого в JavaScript существует специальное обозначение:
var a=10;
a++;
alert(a)
или
var a=10;
++a;
alert(a)
выведет число 11.

Таким образом, чтобы увеличить числовое значение на единицу (выполнить операцию "автоинкремент" - автоприращение), следует использовать удвоенный знак "плюс". Аналогичным образом, чтобы уменьшить числовое значение на единицу (выполнить операцию "автодекремент" - автоуменьшение), следует использовать удвоенный знак "минус":
var a=10;
a--;
alert(a)
или
var a=10;
--a;
alert(a)
выведет число 9.

Зачем для одного и того же действия два обозначения (спереди и сзади имени переменной - "префиксное" и "постфиксное")? Оказывается, что сочетание этих действий с операцией присваивания другой переменной можно трактовать по-разному:
Положение двойного знака Выполняемые действия
Спереди: a=++b; Сначала выполнить операцию автоинкремента (добавить к b единицу), а затем полученное значение присвоить переменной a: b=b+1; a=b;
Сзади: a=b++; Сначала значение b присвоить переменной a, а затем выполнить над b операцию автоинкремента - увеличить значение b на единицу (видимо, для последующего использования): a=b; b=b+1;
Так же JavaScript трактует и знаки автодекремента.

5.4.3. Конкатенация (сцепление) строк.

Знак + используется в JavaScript и еще для одной цели - конкатенации ("склеивания") строк.
Конкатенация двух строк -
это получение новой строки, состоящей из последовательно расположенных конкатенируемых строк

В приведенном ниже примере строка приветствия (g) создается конкатенацией трех строк двумя разными способами. Обратите внимание на то, что во втором способе пробел записан в виде литеральной строки. Такая запись не всегда легко читается, но часто применяется, поскольку сокращает количество необходимых переменных.
var s1="Здравствуйте";
var s2=" ";
var s3="все!";
var g;
// Создадим приветствие:
g=s1+s2+s3;
// То же, но другим способом:
g=s1+' '+s3;
Если с одной из сторон от знака "+" стоит переменная со строковым значением, то JavaScript выполняет операцию конкатенации независимо от того, какое значение имеет другая переменная - строковое или числовое. Следующая программа (3.htm) выводит (странную) строку "1Моя строка":
<SCRIPT LANGUAGE="JavaScript">
<!--
var a=1;
var myString="Мо\я строка";
var b;
b=a+myString;
alert(b);
//-->
</SCRIPT>


5.5. Объекты бродилки

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

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

Как же заставить бродилку открыть другое окно? Ответ прост - создав новый объект Window (Окно).

Но, прежде чем начать создавать новые объекты, посмотрим, как же устроена бродилка с точки зрения JavaScript. Оказывается, с точки зрения JavaScript бродилка - это объект navigator и набор окон - объектов Window:

Сами объекты Window имеют сложную структуру, которую мы изучим ниже. Что же касается объекта navigator, то его свойства необходимо анализировать для настройки ваших программ в том случае, если вы хотите, чтобы они работали с учетом особенностей различных бродилок. Этим мы пока заниматься не будем вовсе.

5.5.1. Окно как объект Window

Текущее окно бродилки - то, в котором работает ваша программа - имеет встроенное в JavaScrit имя ("местоимение" ;-) - window ("окно"). По историческим причинам у этого окна два (а если это кадр - то даже три) встроенных имени. Второе имя текущего окна - self - "само" (а текущего кадра - еще и _self). Любой объект JavaScript может иметь много имен, хотя это и не часто нужно.

Чтобы создать новое окно бродилки, в JavaScript-программе необходимо вызвать встроенную функцию - свойство объекта Window:
window.open(URL, имя_окна, особенности_окна);
// или
self.open(URL, имя_окна, особенности_окна);
Обратите внимание на синтаксис (запись) вызова этой функции. Сначала написано имя объекта - текущего окна (window или self). Затем стоит точка. Эта точка означает, что далее последует уточнение объекта - будет названо имя его свойства - подобъекта или метода (функции, связанной с объектом). В нашем случае это метод (функция, поскольку после имени open стоит открывающая скобка).

Функция window.open() имеет три аргумента. Как правило, все они используются. (А что значит "аргумент функции не используется?" JavaScript позволяет вызывать функции, указывая любое число аргументов. Например, можно написать в программе: window.open(""); - пустая строка вместо URL, имя окну не дано, и создаваемое окно не имеет никаких особенностей - или даже: window.open();).

Смысл аргументов функции window.open() следующий:
Аргументы функции
window.open(URL, имя_окна, особенности_окна)
Аргумент Что значит этот аргумент
URL Строка - адрес того документа, который будет загружен во вновь создаваемое окно.
Если вместо URL указана пустая строка, то создается пустое окно - удобное место для вывода результатов работы программы.
имя_окна Строка - имя создаваемого окна.
Впоследствии, когда в документе, загружаемом в одно из окон, потребуется создать такую ссылку, что переход по ней должен загрузить документ в окно, создаваемое при помощи функции window.open(), в ярлыке <a href=...> необходимо будет добавить атрибут TARGET=имя_целевого_окна 
Как всегда в JavaScript, имя может состоять из латинских букв, знака подчеркивания и цифр, но не должно начинаться с цифры. 
Напомню, что все объекты JavaScript должны иметь разные имена, так что назвать новое окно Window или window нельзя.
особенности_окна Строка - список особенностей создаваемого окна (через запятую без пробелов
Перечень особенностей (связь с текущим окном, размеры, положение и оформление) приведен в следующей таблице. 
Большинство особенностей окна после его создания изменить невозможно
В отличие от первой функции JavaScript, с которой мы познакомились в начале (alert()), функция создания окна возвращает результат своей работы - объект, описывающий вновь созданое окно. Если мы хотим впоследствии что-то делать с этим окном с помощью программы (напрмер, закрыть), то результат работы функции window.open() следует сохранить в значении какой-то переменной (см. примеры в 5.5.1.1.)

Вызов функции window.open(URL) (создание безымянного окна без особенностей) равносилен следующему выбору из меню Netscape Navigator (Communicator): File|New|Navigator Window, - с последующей загрузкой во вновь созданное окно указанного URL.
 
Особенности вновь создаваемого окна
Название 
особенности окна
Запись в 
списке особенностей
Описание Значение по 
умолчанию
      Связи окон
Зависимое окно dependent=0 
dependent=no 
dependent=1 
dependent=yes
(Navigator 4.0) Если 1 (yes), то новое окно создается как подчиненнное (child) текущему. Если пользователь закроет текущее окно, то закроются и все подчиненные dependent=no
      Размеры и положение (<целое> означает целое число)
Общее замечание 1:
Невозможно задать только один размер окна (по высоте или ширине). Если задан только один размер, он игнорируется и создаваемое окно имеет размер текущего окна - как если бы ни один из размеров не был задан
Общее замечание 2:
Создание окна размером менее чем 100x100 пикселов или задание отрицательных или больших смещений (расположение открываемого окна "вне экрана") требует дополнительных действий
Высота height=<целое> (Navigator 2.0 and 3.0) Высота создаваемого окна в пикселах  
Внутренняя 
высота
innerHeight=<целое> (Navigator 4.0) То же, что и height. Высота создаваемого окна в пикселах.  
Внешняя 
высота
outerHeight=<целое> (Navigator 4.0) Наружная высота (с учетом рамки и другого оформления) создаваемого окна в пикселах.  
Ширина width=<целое> (Navigator 2.0 and 3.0) Ширина создаваемого окна в пикселах  
Внутренняя 
ширина
innerWidth=<целое> (Navigator 4.0) То же, что и width. Ширина создаваемого окна в пикселах.  
Внешняя 
ширина
outerWidth=<целое> (Navigator 4.0) Наружная ширина (с учетом рамки и другого оформления) создаваемого окна в пикселах.  
Положение по 
горизонтали
screenX=<целое> (Navigator 4.0) Смещение в пикселах по горизонтали наружного левого верхнего угла окна относительно левого верхнего угла экрана 0, если указано любое значение screenY
Положение по 
вертикали
screenY=<целое> (Navigator 4.0) Смещение в пикселах по вертикали наружного левого верхнего угла окна относительно левого верхнего угла экрана 0, если указано любое значение screenX
Изменяемый размер resizable=0 
resizable=no 
resizable=1 
resizable=yes
Если 1 (yes), то пользователь может изменять размер окна resizable=no
      Оформление и взаимодействие с пользователем
Меню menubar=0 
menubar=no 
menubar=1 
menubar=yes
Создавать ли полосу меню no
Полоса 
инструментов
toolbar=0 
toolbar=no 
toolbar=1 
toolbar=yes
Создавать ли полосу инструментов (с кнопками Вперед, Назад и т.п.) no
Строка адреса location=0 
location=no 
location=1 
location=yes
Создавать ли строку ввода адреса (URL) no
Кнопки указателей 
(полоса 
персональных 
закладок)
directories=0 
directories=no 
directories=1 
directories=yes
Создавать ли полосу указателей (персональных закладок) no
Линейки прокрутки scrollbars=0 
scrollbars=no 
scrollbars=1 
scrollbars=yes
Создавать ли линейки прокрутки no
Статус status=0
status=no
status=1
status=yes
Создавать ли строку статуса в нижней части окна no
"Горячие" клавиши" hotkeys=0
hotkeys=no
hotkeys=1
hotkeys=yes
(Navigator 4.0) Если no (или 0), все горячие клавиши (кроме Ctrl-Q - завершение работы,- и клавиш, связанных с управлением безопасностью) отключаются no

5.5.1.1. Открытие окна с непосредственной загрузкой документа во вновь открываемое окно
Приведем пример открытия окна (4.htm):
<SCRIPT LANGUAGE="JavaScript">
<!--
// Особенности окон, которые мы будем создавать
var newWindowFeatures="dependent=1"; // подчиненное окно
// Зададим размеры будущего окна в виде значений переменных:
var h = 208;
var w = 208;
// Соберем особенности окна в одну строку:
newWindowFeatures = newWindowFeatures+",innerHeight="+h+",innerWidth="+w;
/*
   Создадим окно с именем "board",
   размерами 208х208 пикселов и
   загрузим в него документ "4x4table.htm"
*/
window.open("4x4table.htm","board",newWindowFeatures);
//-->
</SCRIPT>
Обратите внимание на то, что в операции, собирающей особенности окна в единую строку, конкатенируются 5 строк: Возможно, для лучшей читаемости эту операцию следовало бы записать так:
newWindowFeatures = newWindowFeatures
                  + ",innerHeight="
                  + h
                  + ",innerWidth="
                  + w ;
5.5.1.2. Открытие окна с последующей загрузкой документа в него
Можно сначала открыть окно, а затем загрузить в него документ (5.htm):
<SCRIPT LANGUAGE="JavaScript">
<!--
// Особенности окон, которые мы будем создавать
var newWindowFeatures="dependent=1," // подчиненное окно
                    +"innerHeight=208,"
                    +"innerWidth=208";
var board=window.open("","Board",newWindowFeatures);
setTimeout("board.location='4x4table.htm'",3000);
//-->
</SCRIPT>
Отметим, что объект, описывающий вновь созданное окно, сохранен в переменной с именем board. Аналогичное имя (Board) дано и самому окну - оно отличается лишь тем, что начинается с заглавной буквы - значит, это разные имена, и правила именования объектов в программе JavaScript не нарушены. Создаваемое окно пусто - на месте первого аргумента функции window.open("","Board",newWindowFeatures) стоит пустая строка "".

Далее мы знакомимся с еще одной функцией JavaScript - setTimeout() и еще одним свойством окна - location.

Функция setTimeout() имеет 2 аргумента:

  1. строка, содержащая выражение JavaScript, которое нужно выполнить. Это выражение обязательно должно быть заключено в кавычки (=помещено в строку), иначе JavaScript выполнит его немедленно!!! Обратите внимание на то, что в нашем примере это выражение, в свою очередь, содержит строку с именем документа - ее пришлось заключить в апострофы.
  2. число миллисекунд, через которое необходимо начать выполнение указанного в первом аргументе выражения (в нашем примере это 3000 - 3 сек.). По моему опыту, JavaScript обычно несколько опаздывает.
Выражение, которое в приведенном выше примере будет выполнено через 3 сек, - это
board.location='4x4table.htm'
т.е. свойство location объекта board заменяется на значение '4x4table.htm' (программисты говорят, что свойству location объекта board присваивается значение '4x4table.htm' - отсюда название действия, обозначенного знаком "=" - присваивание).
 
Объект board представляет окно, которое мы создали в пятой программе, а свойство location есть у любого окна - это адрес (URL) документа, загруженного в это окно. Таким образом, изменяя это свойство окна, можно загрузить в него любой другой документ. (Осторожно: не пытайтесь загрузить другой документ в то окно, в котором находится документ с вашей программой - бродилка этого не поймет и у нее от таких ваших действий может съехать крыша ;-).

Свойство location, как и любое другое свойство любого объекта, можно скопировать ("прочитать") в другую переменную (6.htm - обратите внимание, что присвоить значение переменной loc2 можно только после того, как в окно Board загружен документ, а вывести результат этого присваивания, т.е. выяснить адрес документа в окне Board - еще позже - в этой простой программе присутствует время!):
<SCRIPT LANGUAGE="JavaScript">
<!--
// Особенности окон, которые мы будем создавать
var newWindowFeatures="dependent=1," // подчиненное окно
                    +"innerHeight=208,"
                    +"innerWidth=208";
var board=window.open("","Board",newWindowFeatures);
var loc1=window.location;
var loc2;
setTimeout("board.location='4x4table.htm'",3000);
setTimeout("loc2=board.location",3100);
setTimeout(
"alert(\'В главное окно загружен документ\'+loc1+\',\\nа во вторичное - \'+loc2)",
      3200);
//-->
</SCRIPT>
Еще один важный момент, относящийся не к объекту окно, а к записи строки с выражением JavaScript в третьем вызове функции setTimeout(). Поскольку апострофы и символ "\n" в ней должны "начать работать" только тогда, когда будет выполняться функция alert(), эти символы необходимо "заэкранировать", чтобы в момент вызова setTimeout() они были бы поняты дословно. Отсюда лишние обратные косые.

5.5.1.3. Открытие окна по запросу
Пример (7.htm)  открытия окна по запросу знакомит вас не с новыми свойствами окна, а с новым способом взаимодействия с пользователем:
<SCRIPT LANGUAGE="JavaScript">
<!--
var newWindowFeatures="dependent=1,innerHeight=208,innerWidth=208";
var answer=window.confirm("Открываем окно?");
if ( answer )
{
  window.open("4x4table.htm","Board",newWindowFeatures);
}
//-->
</SCRIPT>
 Метод (функция) window.confirm() выводит модальное окно, требующее одного из двух ответов:
Текст, выводимый в этом окне - аргумент функции window.confirm(). Эта функция вырабатывает результат - логическое значение (yes/no - да/нет), которое запоминается в переменной answer.

Следующая строка программы содержит новый оператор JavaScript - условный оператор if. Этот оператор имеет следующий синтаксис (см. также расширенный синтаксис оператора if):
if ( условие )
{
  оператор;
  оператор;
  ...
  оператор;
}
Смысл условного оператора таков:

В нашем случае условие очень простое - содержит ли переменная answer значение yes? (Так будет, если наш ответ был "OK"). Если оно выполнено, то программа открывает окно:
{
  window.open("4x4table.htm","Board",newWindowFeatures);
}
 А если нет - не открывает, пропуская вызов метода window.open().

Заметим, что все только что описанные действия происходят ДО появления текста седьмого документа в окне бродилки (щелкните еще раз по ссылке 7.htm и проверьте!). Действительно, наша программа находится в контейнере <HEAD>. А что будет, если ее перенести в конец документа (7a.htm)? Документ на быстрой машине не успеет отобразиться полностью, но часть его будет видна в момент появления вопроса. Из приведенного примера ясно, что временной фактор может быть очень важен при создании сложных приложений с помощью JavaScript.

Еще один пример работы с тем же окном приведен в документе 7b.htm:
<SCRIPT LANGUAGE="JavaScript">
<!--
var newWindowFeatures="dependent=1,innerHeight=208,innerWidth=208";
var board=window.open("","Board",newWindowFeatures);
if ( board.confirm("Заполним окно?") )
{
  board.location="4x4table.htm";
}
//-->
</SCRIPT>
Обратите внимание на две особенности в этой программе (обе они касаются применения метода confirm()):

  1. метод confirm() теперь берется не из объекта window, т.е. не из текущего окна, а из объекта board, т.е. из окна, которое мы только что открыли:
    board.confirm("Заполним окно?")
    Для этого результат вызова метода, открывшего новое окно, пришлось запомнить в переменной board:
    board=window.open(...);
    Тем самым удалось добиться, что модальное окно с вопросом появляется над новым окном, а не над старым, как это было в предыдущих примерах.
    ВЫВОД: методы alert(), confirm() и им подобные следует брать из того объекта, к которому относится сообщение или вопрос, иначе внимание пользователя будет привлечено не к тому объекту.
  2. результат выполнения метода (функции) board.confirm("Заполним окно?") не запомнен в переменной, а использован непосредственно в условии оператора if(). Так следует поступать, если результат выполнения функции требуется единственный раз.

5.5.2. Документ как объект document

До сих пор мы заполняли открываемое окно уже готовым документом. Но в окно, которое открыто с помощью программы JavaScript, можно писать, используя JavaScript. Для этого необходимо применить три метода объекта document, связанного с открытым окном (документ 8.htm):
<SCRIPT LANGUAGE="JavaScript">
<!--
var newWindowFeatures="dependent=1,innerHeight=208,innerWidth=208";
var board=window.open("","Board",newWindowFeatures);
if ( board.confirm("Заполним окно?") )
{
  board.
document.open();
  board.
document.write("<html>");
  board.document.write("<head><title>NEW WINDOW</title></head>");
  board.document.write("<body>");
  board.document.write("<h2>Новое окно!</h2>");
  board.document.write("И в нем что-то есть!");
  board.document.write("</body>");
  board.document.write("</html>");
  board.
document.close();
}
//-->
</SCRIPT>
Сначала следует "открыть" документ для записи методом document.open(). Обратите внимание, что "последовательность называния компонент" следующая:
окно, документ (как компонент окна), метод (документа):
board.document.open(); 
Затем нужные элементы HTML "выводятся" с помощью метода write(). Этот метод есть только у объекта document!

Когда все, что хотели, записано, документ, в который велась запись, необходимо закрыть, применив метод document.close() - к документу в нужном окне!

Как только мы пытаемся что либо вывести в документ, прежнее содержимое этого документа пропадает (9.htm).

5.5.3. Изображение как объект Image

Как известно, в HTML-документ могут быть включены изображения. Для этого используется ярлык <IMG>:
<IMG SRC="источник" ALT="текст" LOWSRC="источник" NAME="имя">

источник - это URL файла изображения (в частности, это может быть имя файла). Изображение, указанное в атрибуте LOWSRC, загружается до изображения, указанного в атрибуте SRC, а затем заменяется на последнее (предположительно первое имеет меньшее разрешение и, соотвественно, существенно меньший объем файла, т.е. быстро загружается);
текст - это текст, выводимый на месте изображения до его загрузки или в случае отказа пользователя от загрузки изображения;
имя - это имя конкретного элемента <IMG>. Атрибут NAME (так же, как и атрибут LOWSRC) стандартизован только в HTML 4.
Такие элементы, входящие в состав HTML-страницы, находят свое отражение в JavaScript в виде свойств объекта document.
5.5.3.1. Формальный подход
Кроме методов, объект document имеет еще и свойства (компоненты). Одним из таких компонентов является набор (в терминологии JavaScript - массив) изображений, входящих в документ. Этот массив называется document.images. Поскольку изображений может быть несколько, необходмо иметь средство указать, с каким именно необходимо иметь дело в данный момент.

Это можно сделать при помощи т.н. индекса. Все изображения, входящие в документ, нумеруются с нуля подряд до некоторого числа в порядке их появления в HTML-тексте документа. При необходимости обратиться к конкретному изображению номер этого изображения (называемый индексом) указывается в квадратных скобках. Ниже приведена программа из документа 10.htm, заменяющая одно изображение (встроенное в документ img1.htm, первоначально загружаемый в окно) на другое:
<SCRIPT LANGUAGE="JavaScript">
<!--
var newWindowFeatures="dependent=1,innerHeight=208,innerWidth=208";
var board=window.open("imge.htm","Board",newWindowFeatures);
if ( board.confirm("Сменим картинку?") )
{
  board.document.images[0].src="img/1.gif";
}
//-->
</SCRIPT>
Операция в выделенной строчке заменяет прежнее значение свойства src объекта board.document.images[0] на новое (img/1.gif), тем самым загружая в документ новое изображение.

5.5.3.2. Временной фактор
Приведенная выше программа работает не всегда. На моем компьютере изображение то сменяется, то нет (большей частью - нет). В чем дело?

К моменту выполнения строки
  board.document.images[0].src="img/1.gif"; 
JavaScript может еще не успеть "осознать", какова структура документа imge.htm, загруженного в окно board тремя строками ранее (window.open("imge.htm","Board",newWindowFeatures); ) - скорость включения новых структур данных из загружаемых документов в среду исполнения JavaScript, из которой они становятся доступными нашим программам, невелика (и нигде не описана). Поэтому JavaScript в лучшем случае не выполняет требуемое действие, а в худшем - выводит сообщение типа:

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

Для того, чтобы ускорить смену изображения, целесообразно загрузить новое изображение в среду JavaScript заранее, до того, как оно потребуется. Это можно сделать, создав объект Image (переменную otherImg для хранения такого объекта), и запомнив в нем (в ней) соответствующее изображение (otherImg.src="img/1.gif"). К сожалению, невозможно совместить создание объекта Image и задание его начального значения.

Объединив эти два действия в одной программе, получим документ 10a.htm:
 
<SCRIPT LANGUAGE="JavaScript">
<!--
var newWindowFeatures="dependent=1,innerHeight=208,innerWidth=208";
var board=window.open("imge.htm","Board",newWindowFeatures);
var otherImg = new Image();
otherImg.src="img/1.gif";
if ( board.confirm("Сменим картинку?") )
{
  setTimeout("board.document.images[0].src=otherImg.src",100);
}
//-->
</SCRIPT>
Заслуживает отдельного обсуждения значение времени задержки. Я не нашел информации по расчету необходимого времени задержки. Во многих программах JavaScript, которые можно найти в Интернет, стоит время, которое я использовал в приведенной программе - 100 мсек (0.1 сек). По-видимому, его в большинстве случаев достаточно, хотя я сталкивался со случаями, когда была необходима задержка в 0.5 сек или достаточна задержка, создаваемая вызовом setTimeout() (т.е. 0 мсек ;-).

5.5.3.3. Именованные изображения
Когда в вашем документе одно - два изображения, нетрудно обратиться к ним по номеру. Но когда изображений много, хотелось бы иметь возможность использовать их имена. Для этого обратимся к файлу imge.htm - в нем изображению дано имя:
<IMG SRC="img/empty.gif" NAME="Flipper">
Это означает, что к этому изображению можно обратиться по имени. Поскольку изображение - компонент (свойство) объекта document, соответствующего HTML-странице, то для обращения к изображению достаточно упомянуть его имя как имя свойства документа (см. файл 10i.htm):
setTimeout("board.document.Flipper.src=otherImg.src",100);

5.5.4. Введение в формы: кнопка и нажатие на нее (onClick)

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

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

5.5.4.1. Форма с кнопкой
В этом разделе мы изучим простейший элемент формы - кнопку, - и простейшее событие, связанное со щелчком мыши по этой кнопке. JavaScript умеет делать с формами многое, но мы оставим изучение работы с формами на другой раз.

Для начала необходимо создать документ с кнопкой. Для этого в документ необходимо вставить контейнерный элемент <FORM> - форму (файл  11.htm):
<FORM NAME="Dummy">
  <INPUT TYPE=BUTTON NAME="Button1" VALUE="Нажмите здесь!">
</FORM>
Обратим внимание на несколько моментов:

Обсудим каждый из этих моментов.
5.5.4.2. Простейшая реакция на событие
Название события, на которое должна реагировать кнопка, вписывается в элемент <INPUT TYPE=BUTTON> как его новый атрибут:
  <INPUT TYPE=BUTTON NAME="Button1" onClick="" VALUE="Нажмите здесь!">
Пока событие только названо (список допустимых названий событий, связанных с каждым элементом HTML-документа, имеется в Рекомендациях по HTML 4): onClick, а значением этого атрибута является пустая строка. Как и имя любого другого атрибута, название события может быть написано любыми буквами - строчными или заглавными или их смесью, как в нашем случае. Названия событий обычно состоят из (английских) предлога и отглагольного существительного, поэтому существует такая традиция написания названий событий: предлог пишется строчными буквами, а первая буква существительного - заглавными (on - при, Click - Нажатии).

Значение атрибута, имя которого совпадает с названием события, - это действие, которое бродилка должна выполнить при возникновении этого события (в нашем случае - нажатии кнопки). В качестве действия может быть написан, например, оператор JavaScript (12.htm - в файле ярлык записан в одной строчке, поскольку имеется печальный опыт странных реакций бродилок на разрыв строки между атрибутами ярлыков; а здесь для лучшей читаемости каждый атрибут ярлыка <INPUT> записан в отдельной строке):
<INPUT
   TYPE=BUTTON
   NAME="Button1"
   onClick="alert('Нажали!');"
   VALUE="Нажмите здесь!"
>
Вторая гипотетическая возможность - описать обработку события целой программой на JavaScript, вытянутой в одну длинную строчку (см. 13.htm - эту строчку здесь невозможно поместить ;-). Во-первых, это неудобно - как в такой программе искать ошибки? Во-вторых (и это более существенно), по неизвестным причинам такие программы, как правило, дают неверные результаты. (Обратите внимание, что текст обработчика события onClick в файле 13.htm слегка отличается от текста программы, изменяющей изображение, который приведен, например, в файле 10i.htm, хотя эти две программы делают одно и то же. Это отличие эксплуатирует две тонкие особенности JavaScript, неявно описанные в документе ECMA-266 - чтобы заставить работать эту простую програму, пришлось немало потрудиться!)

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

5.5.4.3. Пишем функцию для обработки события
Такая функция содержится в файле 14.htm, который функционально эквивалентен предыдущему (13.htm):
<SCRIPT LANGUAGE="JavaScript">  
<!--
var newWindowFeatures="dependent=1,innerHeight=208,innerWidth=208";
var board;
var otherImg = new Image();
otherImg.src="img/1.gif";
function show_and_replace_Img()
{
  board=window.open("imge.htm","Board",newWindowFeatures);
  if ( board.confirm("Сменим картинку?") )
  {
    setTimeout("board.document.Flipper.src=otherImg.src;",100);
  }
}
//-->
</SCRIPT>
...
<FORM NAME="Dummy">
  <INPUT TYPE=BUTTON NAME="Button1"
        onClick="
show_and_replace_Img()"
        VALUE="Нажмите здесь!">
</FORM>
Уже знакомый нам текст разбит на две части. Первая часть содержит описания переменных (newWindowFeatures, board, otherImg); в ней же двум переменным присвоены значения. Вторая часть заключена в фигурные скобки, перед которыми стоит строка
function show_and_replace_Img() 
Эта строка означает, что начинается описание функции - такой части программы, которая будет выполняться позже. Действительно, далее в том же файле мы встречаем то же название (вместе со следующим за ним круглыми скобками) в том месте, где необходимо написать выражение JavaScript, описывающее обработку события onClick. Там, где за круглыми скобками, следующими за названием функции, в свою очередь нет фигурных скобок, происходит вызов функции - программный текст, написанный ранее в описании этой функции, начинает выполняться.

Формальный синтаксис описания функции следующий:
function <имя_функции>(<список_формальных_аргументов>)
{
  оператор JavaScript;
  оператор JavaScript;
  ...
  оператор JavaScript;
}
Блок операторов, заключенный в фигурные скобки, называется телом функции. В теле функции могут использоваться формальные аргументы - переменные, имена которых перечислены через запятую в списке формальных аргументов. При вызове функции в скобках после ее имени указывается список фактических параметров - формальные аргументы заменяются на фактические (см. след. раздел), а тело функции как бы подставляется на место ее вызова, - и выполняется.
 
В нашем случае список формальных параметров функции show_and_replace_Img()пуст, поэтому при ее вызове также не нужно указывать фактические параметры.

5.5.4.4. Обработка событий - функция с параметрами
А что, если захотеть заменять уже знакомую нам пустую картинку не на цифру "1", а на разные числа - в зависимости от нажатой кнопки 15.htm? Такой эффект достигается применением функции с параметром:
<SCRIPT LANGUAGE="JavaScript">
<!--
var newWindowFeatures="dependent=1,innerHeight=208,innerWidth=208";
// Это будет новое окно:
var board;
// Создадим массив для хранения 15-и изображений:
var imgs = new Array(15);
// Заполним созданный массив изображениями:
for ( var i=0; 15>i; ++i )
{
  imgs[i] = new Image();
  imgs[i].src="img/"+(i+1)+".gif";
}
function
show_and_replace_Img(n)
{
  board=window.open("imge.htm","Board",newWindowFeatures);
  if ( board.confirm("Сменим картинку?") )
  {
    setTimeout("board.document.Flipper.src=imgs["+(
n-1)+"].src;",100);
  }
}
//-->
</SCRIPT>
...
<FORM NAME="Dummy">
  <INPUT TYPE=BUTTON NAME="Button1" 
        onClick="
show_and_replace_Img(1)"VALUE=" 1">
  <INPUT TYPE=BUTTON NAME="Button2" 
        onClick="
show_and_replace_Img(2)"VALUE=" 2">
  <INPUT TYPE=BUTTON NAME="Button3" 
        onClick="
show_and_replace_Img(3)"VALUE=" 3">
  <INPUT TYPE=BUTTON NAME="Button4" 
        onClick="
show_and_replace_Img(4)"VALUE=" 4">
...
  <INPUT TYPE=BUTTON NAME="Button15" 
        onClick="
show_and_replace_Img(15)"VALUE="15">
</FORM>
 Нам пришлось немало потрудиться! Для хранения 15-и изображений пришлось создать массив, т.е. переменную с индексом, для чего используется встроенная функция Array(). Эта функция (строго говоря, называемая конструктором массива) имеет один параметр - число элеменов в массиве. Оператор new указывает, что создается новая переменная:
var imgs = new Array(15);
Только что созданный массив способен хранить что угодно, но мы хотим хранить в нем изображения. Поэтому необходимо "пройтись" по всем элементам массива и в каждый "положить" некоторое изображение. Здесь перед нами встает уже не только задача программирования, но и задача проектирования: как задать названия изображений чисел, чтобы этими изображениями было бы легче манипулировать в дальнейшем? Я принял, на мой взгляд, простейшее решение: файл с изображением числа n называется n.gif. Как же "пройтись" по всем элементам массива? Специально для этого предназначен оператор JavaScript for, имеющий следующий синтаксис (обратите внимание, что этот оператор имеет три параметра, отделяемые друг от друга точкой с запятой - эти три параметра, в свою очередь, тоже операторы!) :
for ( <инициализация>; <проверка>; <инкремент> )
{
  оператор JavaScript;
  оператор JavaScript;
  ...
  оператор JavaScript;
}

Оператор for в нашем случае использует специальную переменную i - счетчик цикла:
for ( var i=0; 15>i; ++i )
{
  imgs[i] = new Image();
  imgs[i].src="img/"+(i+1)+".gif";
}
Поэтому инициализация в нашем случае очень проста: создаем переменную i и присваиваем ей начальное значение 0 - элементы массивов в JavaScript нумеруются, начиная с 0:
for ( var i=0;
Проверка тоже проста: в массиве 15 элементов, поэтому, если мы начали счет с 0, закончить следует на 14-м элементе:
for ( var i=0; 15>i;
Можно было бы написать то же условие многими другими способами:
i<15
i<=14
14>=i
15>i
Два последние - предпочтительнее, поскольку "неграмотная" в отношении JavaScript бродилка может принять знак "<" (меньше) за открывающую угловую скобку неизвестного ей ярлыка, и начнет искать закрывающую - ясно, что ничего хорошего из этого не выйдет. Какое из двух условий выбирать для завершения нашего цикла - дело вкуса.

Оператор инкремента в нашем случае - автоинкремент счетчика цикла, увеличивающий его на единицу.
for ( var i=0; 15>i; ++i )
Какой именно автоинкремент применять  - префиксный или постфиксный - все равно, поскольку явная операция присваивания, немедленно использующая новое значение счетчика цикла, отсутствует:
for ( var i=0; 15>i; i++ )
 
Теперь рассмотрим тело нашего цикла. Оно состоит всего из двух операторов: сначала в i-м элементе массива imgs запоминается "пустышка", способная хранить изображение, а затем в эту "пустышку" вписывается имя файла изображения:
for ( var i=0; 15>i; ++i )
{
  imgs[i] = new Image();
  imgs[i].src="img/"+(i+1)+".gif";
}
Рассмотрим каждое из этих действий подробнее.

Номер элемента массива записывается после имени массива в квадратных скобках:
  imgs[i] = new Image(); 
Имя файла изображения "склеивается" из трех частей ("img/", номера изображения и ".gif"):
  imgs[i].src="img/"+(i+1)+".gif"; 
Поскольку изображения содержат числа, начинающиеся с единицы, а элементы массива нумеруются с нуля, для вычисления номера изображения следует к переменной цикла прибавить единицу. Чтобы избежать неоднозначности (у нас в одном выражении с помощью знака "+" конкатенируются строки и складываются числа), арифметическая операция взята в скобки - она будет выполнена первой - перед конкатенацией.

Итак, массив изображений заполнен. Это произошло невидимо для пользователя при загрузке документа  15.htm в бродилку. При нажатии на одну из пятнадцати кнопок возникает событие onClick и вызывается функция show_and_replace_Img() с параметром, соответствующим номеру нажатой кнопки - так мы написали в нашем HTML-документе:
...
  <INPUT TYPE=BUTTON NAME="Button2" 
        onClick="
show_and_replace_Img(2)"VALUE=" 2">
  <INPUT TYPE=BUTTON NAME="Button3" 
        onClick="
show_and_replace_Img(3)"VALUE=" 3">
...
Теперь вступает в дело тело функции show_and_replace_Img(), которое отличается от тела одноименной функции предыдущего (14.htm) примера лишь одной строкой, в которой вычисляется номер того элемента массива, в котором хранится необходимое изображение:
было:
    setTimeout("board.document.Flipper.src=otherImg.src;",100);
стало:
    setTimeout("board.document.Flipper.src=imgs["+(
n-1)+"].src;",100); 
Вот и все!

5.5.5.5. Закрыть окно!
Добавим к единственной кнопке четырнадцатого документа (14.htm) еще одно свойство. Пусть после первого нажатия на нее (открывающего окно) надпись на ней меняется на "Закрыть окно!", а повторное нажатие на ту же кнопку закрывает открытое ранее вспомогательное окно. Это, на первый взгляд, потребует только написания еще одной функции (flip_flop() - см. 16.htm):
var openNew = "Нажмите здесь!";
var closeNew = "Закрыть окно!";
var buttonValue = '';
function
flip_flop()
{
  buttonValue = window.document.Dummy.Button1.value;
  if ( buttonValue == openNew )
  {
    window.document.Dummy.Button1.value = closeNew ;
    show_and_replace_Img();
  }
  else
  {
    window.document.Dummy.Button1.value = openNew ;
    board.close();
  }
}
...
<FORM NAME="Dummy">
  <INPUT TYPE=BUTTON NAME="Button1"
        
onClick="flip_flop()"
        VALUE="&{openNew};"
  >
</FORM>
Но этого оказалось мало - начальную надпись на кнопке не следует писать в HTML-документе дважды (можно один раз и ошибиться), поэтому нам придется освоить еще одну возможность JavaScript:

5.6. Вычисляемое значение атрибута ярлыка HTML

Атрибут  ярлыка  в предыдущем примере содержит необычное, на первый взгляд, значение:
VALUE="&{openNew};"
Конструкция &{<выражение_JavaScript>}; означает:
  1. вычислить указанное выражение_JavaScript и затем
  2. подставить результат на место этой конструкции.
В нашем случае выражение чрезвычайно просто - это значение переменной openNew (т.е. "Нажмите здесь!").

Таким образом можно задавать строго одинаковые значения переменным и атрибутам ярлыков HTML-документа, которые должны иметь значение, совпадающее со значением переменной. В выражении JavaScript, используемом для задания значения атрибута, можно использовать и вычисления, например, можно было бы написать
VALUE="&{openNew+'..'};"
 для того, чтобы добавить отточие к тексту, содержащемуся в переменой openNew.

Рассмотрим внимательнее функцию flip_flop(). Для ее работы заранее приготовлены три переменных:

Назначение первых двух - хранить сообщения, поочередно выводимые на кнопке. Третья хранит последнее сообщение, записанное нашей програмой на кнопке. Сама функция состоит из двух операторов:
  buttonValue = window.document.Dummy.Button1.value ; 
и
  if ( buttonValue == openNew )
  {
    window.document.Dummy.Button1.value = closeNew ;
    show_and_replace_Img();
  }
  else
  {
    window.document.Dummy.Button1.value = openNew ;
    board.close();
  }
 
Первый просто запоминает в переменной buttonValue ту строку, которая служила надписью на кнопке (обратите внимание, как мы "добрались" до этой строки: Dummy - это имя формы, Button1 - имя кнопки в этой форме, value - значение атрибута VALUE, т..е. то, что отображается на кнопке).

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

Второй оператор - это расширенная форма оператора if:
if ( условие)
{
  оператор;
  оператор;
  ...
  оператор;
}
else
{
  оператор;
  оператор;
  ...
  оператор;
}
Если условие не выполнено, то блок операторов в фигурных скобках, следующих непосредственно за if ( условие ), пропускается и, при наличии ключевого слова else, выполняется блок, следующий за этим словом. Если условие выполнено, то, напротив, исполняется первый блок, а второй пропускается.

Проверяемое условие - надпись на кнопке должна предлагать открыть окно:
  if ( buttonValue == openNew ) 
Сами блоки операторов в нашем случае просты и состоят из двух операторов каждый. Первый из них изменяет надпись на кнопке, второй - выполняет требуемое действие (открывает или закрывает окно).


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

Программа, реагирующая на все описанные действия пользователя, приведена в 17.htm. Текст документа 17.htm можно посмотреть в отдельном окне. В ней для хранения текста, выводимого на кнопке, используется отдельная переменная (refresh). Это необходимо, так как при перерисовке документа после изменения размера окна, надпись на кнопке должна быть правильно восстановлена (а в предыдущей программе она восстанавливалась из той переменной, в которой хранилось ее "будущее" значение - то, которое должно было бы возникнуть на кнопке после ее нажатия). Для проверки того, не закрыто ли уже вспомогательное окно, используется свойство этого окна (board.closed). С помощью свойства Window.closed можно проверить, не закрыто ли любое окно - на место Window следует подставить имя соответствующей переменной, связанной с окном.


5.8. Программа в одном окне - действие в другом

В нашем продвижении к игре в "15" создадим теперь "реагирующее игровое поле". Это можно сделать, как всегда, многими способами. Мы обсудим только один из них. Теперь объект, на котором должно быть сосредоточено наше внимание - игровое поле. Будем хранить HTML-документ, описывающий игровое поле, в файлах с именами 4x4-v.htm, где v - номер версии файла. Задача, решаемая с помощью первого (4x4-1.htm) варианта игрового поля, - научиться идентифицировать клетки поля. Для этого клетки поля необходимо сделать чувствительными к нажатию мышью (реагирующими на событие onClick). Изображение (а наше поле - таблица 4*4, заполненная пока 16-ю одинаковыми изображениями) как элемент HTML само по себе нечувствительно. Его можно сделать чувствительным, заключив его в элемент "ЯКОРЬ" (<A>) или добавив атрибут USEMAP. Я выбрал первый вариант. Вот типичная (первая) строка описания ячейки таблицы из 4x4-1.htm (в файле приведенный фрагмент вытянут в одну строку!):
<TD><A
       HREF="#"
       onClick="
opener.move(0,0);"><IMG
                                           SRC="img/empty.gif"
                                           HEIGHT=48
                                           WIDTH=48
                                           BORDER=0></A></TD>
Проанализируем написанное в этой строке.

5.9. Ссылка на функцию JavaScript в элементе <A>

Изменим, как я обещал, адрес перехода в игровом поле для полной неподвижности изображения при переходе (19.htm и 4x4-2.htm ):
<TD><A HREF="JavaScript:opener.move(0,0);"><IMG SRC="img/empty.gif"
                                                   HEIGHT=48
                                                   WIDTH=48
                                                   BORDER=0></A></TD>
Оказывается, JavaScript - это протокол, а адрес для этого протокола - функция! (URL - это протокол:адрес). При этом никаких смещений документа не происходит.

5.10. Случайные числа. Объект Math

Порождение различных вариантов игры в "15" требует привлечения (псевдо-)случайных чисел. Приведу часть файла 20.htm, содержащую новые, по сравнению с 19.htm, строки:
var game = new Array(
           new Array(0,0,0,0),
           new Array(0,0,0,0),
           new Array(0,0,0,0),
           new Array(0,0,0,0)
                   );
 
function move(row,col)
{
  board.alert(game[row][col]);
}
 
function fill()
{
  var cell;
  var g = new Array(-1,-1,-1,-1,-1,-1,-1,-1,
                    -1,-1,-1,-1,-1,-1,-1,-1);
  for (var i=0; i<16; )
  {
    cell = Math.floor(Math.random()*16);
    if ( g[cell] != 'undefined' ) continue;
    g[cell]=i;
    board.document.images[cell].src
                    ="img/"+i+".gif";
    game[(cell-cell%4)/4][cell%4]=i++;
  }
}
Создаем двумерный массив 4*4
(строк * столбцов)
и заполняем его нулями.
Этот массив будет хранить
информацию о ходе игры


Ход - щелчок мышью по клетке

Пока - все еще сообщение о
том, какое число в клетке

Начальное заполнение игрового
поля:
Случайная ячейка
Пустой вначале массив -
отметки о заполнении ячеек


Случайное число от 0 до 15
Если такое уже было ...
А если не было - отметим
Запишем очередную картинку
  на ее место
А номер картинки -
  в массив игры (game)
Случайные числа - свойства встроенного в JavaScript объекта Math. Этот объект имеет большое количество методов из различных областей математики. В частности, метод Math.random() порождает случайное число в интервале от 0 до 1. Моя идея - последовательно расставить числа от 0 до 15 в случайные ячейки нашего игрового поля. Поэтому случайным образом порождается номер ячейки: случайное число из интервала (0,1) умножается на 16, - получается число в интервале (0,16), а затем с помощью метода Math.floor() от полученного числа отбрасывается дробная часть - получается целое число от 0 до 15.

Если ячейка с полученным номером уже занята ( g[cell] != 'undefined' ), то происходит следующая попытка определить случайный номер ячейки.

Если же ячейка свободна, то в нее ставится очередное целое число (g[cell]=i;), номер ячейки используется как номер позиции изображения, которое нужно внести в игровое поле, а номер файла изображения равен i (board.document.images[cell].src="img/"+i+".gif";). Это же число следует записать во внутреннее представление игрового поля - двумерный массив game[][]. Здесь приходится рассчитать номера строки и столбца, использовав деление с остатком (a%b - целочисленный остаток от деления a на b).


6. Собираем все вместе

Осталось сделать последний шаг - написать функцию move(row,col), такую, чтобы она действительно переставляла бы изображения. Задачу перестановки пары изображений необходимо разделить на несколько этапов:
  1. Определить, возможно ли вообще подвинуть число (клетка, по которой произведен щелчок, не должна быть пустой, т.е. должна содержать число, которое больше нуля);
  2. Определить, какая из соседних клеток - пустая;
  3. Переставить местами имена файлов изображений, выводимых в упомянутых клетках;
  4. Сделать отметку в массиве game[][].
 Такое решение возможно, но я избрал другой путь (21.htm). Будем пытаться двигать шашку с числом во все четыре стороны по очереди - если подвинется, то и хорошо:
function move(row,col)
{
  if ( swap(row, col,  1, 0) ) { return; }
  if ( swap(row, col, -1, 0) ) { return; }
  if ( swap(row, col, 0, -1) ) { return; }
  if ( swap(row, col, 0,  1) ) { return; }
}


Возможность реального перемещения определяется в функции swap(rowFrom,colFrom,rowD,colD).

Смысл аргументов этой функции следующий:

Попутно отмечу, что, как оказалось, нельзя писать "+1" - в JavaScript нет унарного (одноместного) оператора "+", аналогичного оператору "-".

Эта же функция и выполняет перестановку:
function swap(rowFrom,colFrom,rowD,colD)
{
  var from = rowFrom*4+colFrom;
  var rowTo = rowFrom + rowD ;
  if ( 0 > rowTo || rowTo > 3 ) return false;




  var colTo = colFrom + colD ;
  if ( 0 > rowTo || colTo > 3 ) return false;




  var gf   = game[rowTo][colTo];

  if ( gf != 0 ) return false;


  var to   = rowTo  *4+colTo;


  var gt   = game[rowFrom][colFrom];

  board.document.images[from].src
                ="img/"+gf+".gif";
  board.document.images[to].src
                ="img/"+gt+".gif";
  game[rowTo][colTo]     = gt;


  game[rowFrom][colFrom] = gf;



  return true;
}

Индекс для массива 
  изображений ("откуда")
Строка "куда"
Если строка "куда"
  отрицательная или 
  четвертая, -
  без движения

Столбец "куда"
Если столбец "куда"
  отрицательный или 
  четвертый, -
  без движения

Что же стоит в клетке
  "куда"?
Если эта клетка непуста -
  без движения

Индекс для массива 
  изображений ("куда")

Что же стоит в клетке
  "откуда"?
Сменим изображение
  "откуда"
Сменим изображение
  "куда"
Сменим внутреннее
  представление
  клетки "куда"
Сменим внутреннее
  представление
  клетки "откуда"
Скажем, что
  движение произошло



7. Заключение

Вот и пришла пора остановиться. Размер этого файла превысил 120K.

Из наиболее важных задач теперь - сделать так, чтобы приведенные примеры не "подвешивали" Netscape Navigator 3.02 (в Windows 3.11 так, что приходится перезагружать компьютер), а MS Internet Explorer 4.0 не говорил бы, что сценарии JavaScript, которые ему подсунули, заставляют его работать слишком медленно, и не предлагал бы прекратить работу этих сценариев.

Но это в следующий раз.


Используются технологии uCoz