|
@@ -0,0 +1,302 @@
|
|
|
+# Занятие 3. Циклы и массивы.
|
|
|
+
|
|
|
+## Отладка
|
|
|
+
|
|
|
+**Developer Tools** содержит в себе множество средств отладки кода. Для хорошего понимания управляющих конструкций (**условий** и **циклов**) полезно
|
|
|
+разобраться с **пошаговой отладкой** - выполнением кода по шагам. Это позволяет увидеть, какие блоки кода выполняются или не выполняются в условных
|
|
|
+операторах и каковы значения переменных в каждый момент времени выполнения кода.
|
|
|
+
|
|
|
+Для начала пошаговой отладки устанавливается **точка останова** - строка кода, с которой обычный режим выполнения прерывается и начинается отладка по шагам.
|
|
|
+В **Developer Tools** найдите вкладку *Source*, в ней свой файл c кодом, и кликните на номере нужной строки слева от текста кода.
|
|
|
+
|
|
|
+Если вы используете [repl.it](http://repl.it), другие **онлайн-IDE** или **console**, то у вас будут определенные сложности с нахождением
|
|
|
+вашего кода и строки в нём. Поэтому вы можете вставить ключевое слово `debugger` в ваш код - это работает так же, как **точка останова** на
|
|
|
+строке в Developer Tools.
|
|
|
+
|
|
|
+### Отладка по шагам.
|
|
|
+
|
|
|
+**Пошаговая отладка** позволяет детально заглянуть в процесс выполнения вашего кода - вы можете узнать всё ли работает так, как нужно, в любой строке и таким
|
|
|
+образом упростить поиск логических ошибок в коде. Основные операции:
|
|
|
+- **Step over next function call** (**F10**) - следующий шаг/оператор в вашем коде. После выполнения каждой команды вы можете ознакомится со значениями
|
|
|
+переменных, наведя на них курсор мыши, написав их в консоли, или же используя вкладку Watch
|
|
|
+- **Resume script execution** (**F8**) - переход из режима отладки по шагам в обычный режим выполнения кода. Таким способом вы пропускаете хорошо отлаженные
|
|
|
+части кода. Этот режим может быть прерван следующей **точкой останова** или ключевым словом `debugger` в коде.
|
|
|
+
|
|
|
+### Пошаговая отладка и консоль.
|
|
|
+
|
|
|
+Очень удобно использовать консоль и пошаговую отладку одновременно. Консоль предоставляет все переменные и их текущие значения, которые сейчас есть в
|
|
|
+отлаживаемом коде, таким образом вы можете поэкспериментировать с этими значениями и, например, запустить из консоли следующий проблемный оператор в коде
|
|
|
+или его часть для нахождения логической ошибки.
|
|
|
+
|
|
|
+### Задание 1
|
|
|
+
|
|
|
+Поиграться с вашим ДЗ, добавив туда точки останова, и посмотреть, чему равны переменные и как ведут себя `if` и `switch` в зависимости от значения переменных.
|
|
|
+
|
|
|
+## Циклы.
|
|
|
+
|
|
|
+**Цикл** - последовательность операторов, которая повторяется.
|
|
|
+
|
|
|
+**Цикл** состоит из:
|
|
|
+- тела цикла, т. е. блока кода, который повторяется,
|
|
|
+- условия, которое проверяется перед очередным повтором цикла.
|
|
|
+
|
|
|
+Однократное выполнение тела цикла называется **итерацией**.
|
|
|
+
|
|
|
+### Ключевые слова `break` и `continue`.
|
|
|
+
|
|
|
+Эти ключевые слова применяются в теле и позволяют изменять логику работы цикла:
|
|
|
+
|
|
|
+- `break` обрывает выполнение цикла в любом месте тела - программа продолжается после цикла;
|
|
|
+- `continue` обрывает выполнение текущей *итерации* и начинает следующую итерацию.
|
|
|
+
|
|
|
+### Цикл `while`
|
|
|
+
|
|
|
+Цикл `while` выполняется, пока условие истинно и прекращает свое выполнение как только условие становится ложно:
|
|
|
+
|
|
|
+```javascript
|
|
|
+var password = '';
|
|
|
+var rightPassword = 'qwerty';
|
|
|
+
|
|
|
+while (password != rightPassword){ //Пока пароль не равен верному...
|
|
|
+ password = prompt('Введите пароль:', ''); //спрашивать пароль
|
|
|
+} //возвращаемся на while (....)
|
|
|
+```
|
|
|
+
|
|
|
+Цикл `while` в некотором смысле схож с `if` - тело выполняется если условие верно; однако `if` выполняет тело однократно, а `while` выполняет
|
|
|
+тело *пока* условие верно.
|
|
|
+
|
|
|
+
|
|
|
+#### `break`
|
|
|
+
|
|
|
+```javascript
|
|
|
+var password = '';
|
|
|
+var rightPassword = 'qwerty';
|
|
|
+
|
|
|
+while (password != rightPassword){ //Пока пароль не равен верному...
|
|
|
+ password = prompt('Введите пароль:', ''); //спрашивать пароль
|
|
|
+ if (password == null){ //пользователь нажал отмену...
|
|
|
+ break; //прерываем цикл
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### `continue`
|
|
|
+
|
|
|
+```javascript
|
|
|
+var user = '';
|
|
|
+var rightUser = 'admin';
|
|
|
+var password = '';
|
|
|
+var rightPassword = 'qwerty';
|
|
|
+
|
|
|
+while (user != rightUser || password != rightPassword){ //Пока пользователь не равен верному или пароль не равен верному...
|
|
|
+ user = prompt('Введите имя пользователя:', ''); //спрашивать пользователя
|
|
|
+ if (user != rightUser){ //нет смысла спрашивать пароль, если пользователь неверный, поэтому...
|
|
|
+ continue; //новая итерация.
|
|
|
+ }
|
|
|
+ password = prompt('Введите пароль:', ''); //спрашивать пароль
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Цикл `do ... while`
|
|
|
+
|
|
|
+Этот цикл называется циклом с *постусловием*, то есть проверка условия выхода из цикла происходит не *перед* а *после* выполнения тела цикла. Таким образом,
|
|
|
+цикл с *постусловием* выполняется **хотя бы один раз**. Для нашего примера этот цикл подходит лучше, чем обычный `while`. Почему?
|
|
|
+
|
|
|
+```javascript
|
|
|
+var password = '';
|
|
|
+var rightPassword = 'qwerty';
|
|
|
+
|
|
|
+do{
|
|
|
+ password = prompt('Введите пароль:', ''); //спрашивать пароль
|
|
|
+}while (password != rightPassword) //Пока пароль не равен верному...
|
|
|
+```
|
|
|
+
|
|
|
+### Цикл `for`
|
|
|
+
|
|
|
+Это самый сложный и мощный цикл, в синтаксисе заголовка которого, кроме условия, присутствуют еще и другие операции:
|
|
|
+- инициализация, т. е. то, что делается перед началом цикла
|
|
|
+- условие продолжения (как в `while`)
|
|
|
+- операции, которые выполняются после каждой итерации
|
|
|
+
|
|
|
+В общем виде цикл `for` выглядит так:
|
|
|
+```javascript
|
|
|
+for (init1,init2,...;condition;iter1,iter2...){
|
|
|
+....
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Где:
|
|
|
+- `initN` - это те или иные инициализирующие операторы, которые выполняются *перед* началом выполнения цикла
|
|
|
+- `condition` - условие продолжения
|
|
|
+- `iterN` - операции, выполняющиеся после какждой *итерации*
|
|
|
+
|
|
|
+```javascript
|
|
|
+for (var i=0;i<10;i++){
|
|
|
+ console.log(i);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Этот цикл считает от 0 до 9, каждую итерацию выводя значения i в консоль.
|
|
|
+**Вопрос**: чему будет равен i после цикла?
|
|
|
+
|
|
|
+#### Задание
|
|
|
+Напишите аналогичный цикл `while`
|
|
|
+
|
|
|
+```javascript
|
|
|
+for (var i=10,str="";i>0;i--,str+="#"){
|
|
|
+ console.log(i, str);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**Вопрос**: чему будет равен i и str после цикла?
|
|
|
+#### Задание
|
|
|
+Напишите аналогичный цикл `while`
|
|
|
+
|
|
|
+Таким образом становится ясно, что `for` - не более чем сокращенная форма `while`, или, другими словами, *синтаксический сахар*.
|
|
|
+
|
|
|
+### Вложенные циклы
|
|
|
+
|
|
|
+**Циклы** могут быть *вложенными*, т. е. исполняться один внутри другого. В таком случае на **каждую** *итерацию* внешнего цикла приходятся *все* *итерации*
|
|
|
+вложенного. Такие циклы часто употребляются для работы с дву- и более мерными данными или отображениями (таблицы, картинки, массивы и так далее)
|
|
|
+
|
|
|
+Например:
|
|
|
+
|
|
|
+```javascript
|
|
|
+var i = 'a';
|
|
|
+var str = "";
|
|
|
+for (j=0;j<10;j++){
|
|
|
+ str += i;
|
|
|
+}
|
|
|
+console.log(str);
|
|
|
+```
|
|
|
+Таким образом мы можем создать строку любой длины с любым символом. А теперь оборачиваем этот цикл внешним:
|
|
|
+
|
|
|
+```javascript
|
|
|
+for (var i=0;i<10;i++){
|
|
|
+ var str = "";
|
|
|
+ for (j=0;j<10;j++){
|
|
|
+ str += i;
|
|
|
+ }
|
|
|
+ console.log(str);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### Задание
|
|
|
+
|
|
|
+Напишите вложенный цикл, который будет создавать HTML для таблицы умножения. Используйте тэги `table`, `tr`, `td`. Таблица должна создаваться в
|
|
|
+строковой переменной. Для вывода этой переменной используйте `document.write`.
|
|
|
+
|
|
|
+
|
|
|
+## Массивы
|
|
|
+
|
|
|
+**Массив** - это упорядоченная структура данных, состоящая из нумерованных ячеек. Нумерация идет от 0. Например строка (`String`) - массив символов.
|
|
|
+Доступ к ячейкам массива происходит по её номеру в квадратных скобках:
|
|
|
+
|
|
|
+```javascript
|
|
|
+var myName = "asmer"
|
|
|
+myName[0]
|
|
|
+myName[4]
|
|
|
+myName.length
|
|
|
+```
|
|
|
+Для оперирования с массивами зачастую используются циклы.
|
|
|
+
|
|
|
+#### Задание
|
|
|
+Выведите какую-либо строку побуквенно, используя цикл `for`. Длина массива или строки находится в свойстве `length`.
|
|
|
+
|
|
|
+### Определение массива
|
|
|
+
|
|
|
+Массивы можно определять несколькими способами
|
|
|
+```javascript
|
|
|
+var oopWay = new Array(1,2,3);
|
|
|
+var inlineWay = ["some", "other", "array'"];
|
|
|
+```
|
|
|
+
|
|
|
+### Операции с элементами массива
|
|
|
+В общем те же самые, что и с обычными переменными. Просто не забудьте добавить квадратные скобки и индекс (номер элемента):
|
|
|
+
|
|
|
+```javascript
|
|
|
+var oopWay = new Array(1,2,3);
|
|
|
+var inlineWay = ["some", "other", "array'"];
|
|
|
+
|
|
|
+oopWay[0]++
|
|
|
+oopWay[2] = oopWay[0] - oopWay[1]
|
|
|
+inlineWay[3] = inlineWay[0] + inlineWay[1] + inlineWay[2]
|
|
|
+```
|
|
|
+
|
|
|
+Для обхода всего массива используйте цикл `for`:
|
|
|
+```javascript
|
|
|
+for (var i=0;i<arr.length;i++){
|
|
|
+ //какие-то операции с arr[i]
|
|
|
+ console.log(arr[i])
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### Задание
|
|
|
+Перепишите
|
|
|
+```javascript
|
|
|
+inlineWay[3] = inlineWay[0] + inlineWay[1] + inlineWay[2]
|
|
|
+```
|
|
|
+так, что бы можно было сконкатенировать массив с любым количеством элементов, используя цикл `for`.
|
|
|
+
|
|
|
+### Присвоение, сравнение, копирование массивов и различия со строками.
|
|
|
+
|
|
|
+В отличие от всех тех типов, которые вы видели ранее, массивы ведут себя как полноценные *объекты*. Это значит, что при присвоении переменных, содержащих
|
|
|
+массив, создание нового массива **не** происходит, и переменная ссылается на тот же массив:
|
|
|
+
|
|
|
+```javascript
|
|
|
+a = b = [1,2,3]
|
|
|
+//[1, 2, 3]
|
|
|
+a == b
|
|
|
+//true
|
|
|
+a[0] = 500
|
|
|
+//500
|
|
|
+a
|
|
|
+//[500, 2, 3]
|
|
|
+b
|
|
|
+//[500, 2, 3]
|
|
|
+```
|
|
|
+
|
|
|
+Для создания копии массива (чего обычно ожидают от присвоения), существует метод `slice`:
|
|
|
+```javascript
|
|
|
+a = b.slice()
|
|
|
+//[500, 2, 3]
|
|
|
+a
|
|
|
+//[500, 2, 3]
|
|
|
+a[0] = 1
|
|
|
+//1
|
|
|
+b
|
|
|
+//[500, 2, 3]
|
|
|
+a
|
|
|
+//[1, 2, 3]
|
|
|
+a == b
|
|
|
+//false
|
|
|
+```
|
|
|
+
|
|
|
+Однако копия не равна оригиналу несмотря на одинаковое содержимое:
|
|
|
+```javascript
|
|
|
+a
|
|
|
+//[1, 2, 3]
|
|
|
+b
|
|
|
+//[500, 2, 3]
|
|
|
+b[0] = 1
|
|
|
+//1
|
|
|
+b
|
|
|
+//[1, 2, 3]
|
|
|
+a == b
|
|
|
+//false
|
|
|
+```
|
|
|
+
|
|
|
+Пустой массив равен false:
|
|
|
+```javascript
|
|
|
+[] == false
|
|
|
+//true
|
|
|
+!![]
|
|
|
+//true эта проверка не работает для объектов, кроме null
|
|
|
+false == []
|
|
|
+//true
|
|
|
+[] == []
|
|
|
+//false ведь это два разных массива
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+### Практикум по методам класса Array
|