Книга: JavaScript. Учебник начального уровня
Уже можно играть
Уже можно играть
Продолжу серию статей про программирование для JavaScript. Сегодняшняя статья рискует закончить что–то вроде учебника по этому языку. В вашего сапёра после этой главы уже можно будет играть. Конечно, останется ещё ряд недоделок, например, стоит добавить сообщения при выигрыше и при проигрыше, нужно также сделать так, чтобы при открытие ячейки, рядом с которой нет бомб автоматически открывались также все её соседи. Ещё было бы не плохо сделать возможность выбирать размер поля и количество бомб на нём, добавить возможность помечать ячейки как ячейки с бомбами.
В общем при большом желании можно ещё писать и писать. Однако, дело в том, что ничего принципиально нового мы при этом не пройдём, с теми знаниями, что мы уже прошли всё это и так можно сделать. Возможно стоит только сделать ряд опций, посмотрим.
Сегодня впервые я решил не приводить весь код программы, так как изменения коснулись только функции initTable. Вот во что она превратилась:
var mines = new minesClass(10, 10, 10);
function checkCell(i, j)
{var tbl = document.getElementById(«tbl»);
var cell = tbl.rows[i].cells[j];
var s = mines.checkCell(i, j);
cell.innerHTML = s;
if (s == "*")
cell.bgColor = 'red';}
function initTable()
{var tbl = document.getElementById(«tbl»);
for (var i = 0; i < mines.rowCount; i++)
{var row = tbl.insertRow(i);
for(var j = 0; j < mines.colCount; j++)
{var cell = row.insertCell(j);
cell.innerHTML = '?';
function SetCellClick(i, j)
{cell.onclick= function() {checkCell(i, j)};};
SetCellClick(i, j);}}}
Давайте по порядку. Строчку «var mines = new minesClass(10, 10, 10);" я перенёс наверх, чтобы переменная mines стала доступна из других функций (напомню, что переменная, объявленная внутри функции доступна только внутри этой функции, а «внешние» переменные доступны также в других функциях). Нам потребуется использовать эту переменную в функции checkCell, которую мы выделили из функции initTable.
По сути, в функции checkCell мы получаем из таблицы ячейку с i-ой строкой и j-ым столбцом и присваиваем ей текст, соответствующий количеству бомб рядом (раньше мы это делали непосредственно при инициализации таблицы). Для получения ссылки на ячейку, мы получаем ссылку на таблицу с помощью метода getElementById заранее предопределённой переменной document. Далее мы получаем ссылку на нужную строку, обращаясь к полю rows таблицы (это массив, поэтому после имени поля в квадратных скобках указываем индекс) и сразу же обращаемся к полю cells строки (это тоже массив) для получения искомой ссылки на ячейку.
Последующие строки функции checkCell мы перенесли из функции initTable без изменений.
Ну и последнее о чём осталось рассказать — функция initTable. Несколько строчек мы оттуда унесли и появилась, несколько добавили:
cell.innerHTML = '?';
function SetCellClick(i, j)
{cell.onclick= function() {checkCell(i, j)};};
SetCellClick(i, j);
С первой строкой, думаю, проблем не будет, а вот дальше придётся применить один интересный приём под названием замыкание. Этот метод нашёл широкое применение в JavaScript, не знаю используется–ли он в других языках, не сталкивался, а тут без него ряд задач сделать крайне сложно.
Так вот, зачем же мы пишем так:
function SetCellClick(i, j)
{cell.onclick= function() {checkCell(i, j)};};
SetCellClick(i, j);
и почему нельзя написать просто так:
cell.onclick= function() {checkCell(i, j)};
Чтобы ответить на этот вопрос, давайте попробуем поставить себя на место интерпретатора. Как ему определить, что вам в качестве параметра функции checkCell нужны именно конкретные значения переменных i и j в данный момент, а не значения этих переменных в момент вызова функции. Не буду сейчас загромождать вам мозг понятием ссылок и указателей, с помощью которых зачастую подобные проблемы решаются в других языках, в JavaScript, насколько мне известно таких понятий нет.
Так вот, чтобы в качестве параметров функции checkCell в будущем брались те значения переменных i и j, которые они имеют в момент присваивания, делается такой хитрый приём: создается местная функция внутри которой и происходит присваивание. Фокус в том, что в этом случае используются не долгоживущие переменные, объявленные в функции initTable, а короткоживущие параметры функции SetCellClick.
Всем пока.
- Когда нужен постскриптум в бизнес-тексте?
- Что делать, если при установке принтера появляется сообщение Невозможно завершение операции. Подсистема печати недоступн...
- Расширенные возможности указания пользовательских планов
- Использование переменной окружения ISC_PATH
- Возможности, планируемые к реализации в следующих версиях
- SET TERM больше не нужен в isql
- 24.1. Расширение возможностей Панели задач
- Установка системы на уже подготовленный жесткий диск
- Возможности SSH
- Глава 2 Обнаружение адреса
- Глава 10 Возможности подсистемы хранения данных в различных версиях Windows NT
- Глава 1 Предел возможностей иерархии в мире перемен