05. Основы JavaScript (часть 4)

Циклы

Основная задача циклов — сделать одно и то же действие какое-то количество раз. В JavaSctipt есть три вида циклов, описанных ниже. У циклов есть условие и его тело.

while

У данного вида циклов достаточно простой синтаксис.

while (conditions) {
  // код, который выполняется в случае соблюдения условий
}

Цикл будет выгоняться, пока условие будет истинным. Например:

let x = 0;

while (x < 3) {
  console.log(x);
  x++;
} 

Немного подробнее разберем этот код. Для начала мы создаем переменную и присваиваем ей значение 0. Дальше начинаем запись цикла, условием его выполнения будет когда значение x будет меньше 3.

При первой итерации цикла у нас значение равно 0, дальше мы выводим значение этой переменной в консоль, а затем увеличиваем значение x на 1 (делаем это с помощью двойного плюса «++»).

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

do while

По сути является тем же циклом while, но сначала выполняется его тело, а затем проверяется условие.

let x = 0;

do {
  console.log(x);
  x++;
} while (x < 3);

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

for

Этот цикл наиболее сложный как по синтаксису, так и по восприятию. При этом является наиболее часто используемым.

Синтаксис следующий:

for (начало; условие; шаг) {
  // тело цикла
}

Теперь немного подробнее о том, как он работает:

  1. Выполняется «начало»
  2. Если условие истинно, тогда выполняется тело
  3. Выполняется шаг

Разберем пример:

for (let x = 0; x < 3; x++) {
  console.log(x);
}

И так, что здесь что означает:

  1. Начало — «let x = 0» выполняется один раз при входе в цикл.
  2. Условие — «x < 3» проверяется при каждой итерации цикла.
  3. Шаг — «x++» выполняется ПОСЛЕ тела цикла на каждой итерации ПЕРЕД проверкой условий.

Шаг не обязательно должен увеличивать или уменьшать переменную. Он может являться каким-то выражением, которое так или иначе влияет на переменную. Например, x*3.

Прерывание цикла «break»

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

let sum = 0;

while (true) {
  let value = +prompt('Введите число', '');
  if (!value) break;
  sum += value;
}

console.log('Сумма' + sum);

Разберем подробнее:

  1. Создаем переменную и назначаем ей значение
  2. В условиях цикла у нас присутствует только true, что означает по сути бесконечный цикл.
  3. Далее мы создаем переменную и присваиваем ей в качестве значения, которое ведет пользователь (используем для этого prompt). Перед prompt стоит +, как известно, унарный плюс преобразует строку, введенную пользователем в число и мы не получим ошибку типа NaN.
  4. Далее у нас есть условный оператор. Как известно он сработает тогда, когда значение условия будет истинно. В нашем случае, если value не будет иметь значений, значит условие будет истинно и в этом случае мы прерываем выполнение цикла директивой break.
  5. Дальше мы назначаем переменной sum новое значение путем сложения текущего ее значения и нового из переменной value.
  6. Выводим в консоль результат.

Если коротко описать работу цикла, то он работает до тех пор, пока пользователь не введет пустое значение (или что-то, на что реагирует условный оператор и прервет его выполнение).

Переход к следующей операции «continue»

Эта директива является одной из вариаций break, но не прерывает цикл, а переходит к следующей итерации, минуя выполнение оставшейся части тела цикла.

for (let x = 0; x < 10; x++) {
  if (x % 2 == 0) {
    continue;
  }
  console.log(x);
}

Теперь с пояснениями:

  1. Обозначаем условия для цикла for: выполняем цикл, пока x < 10 с каждой итерацией увеличивая его на 1.
  2. В теле присутствует условные оператор, в качестве условий мы делаем проверку на четность с помощью оператора деления с остатком «%». В итоге, если остаток от деления равен 0, число является четным и мы выполняем директиву continue, то есть переходим к следующей итерации цикла, не выполняя тело цикла, находящееся ниже.
  3. В консоль выводятся только нечетные значения переменной x.

Конструкиця switch

Конструкция switch может заменить собой сразу несколько условных операторов if и сократить запись, тем самым сделать код более читаемым.

switch содержит один или несколько блоков case и необязательный default.

let a = 2 + 2;

switch (a) {
  case 3: // равносильно if (a === 3)
      console.log('Мало');
      break;
  case 4: // равносильно if (a === 4)
      console.log('Точно');
      break;
  case 5: // равносильно if (a === 5)
      console.log('Много');
      break;

  default:
      console.log('Нет таких значений');
}

В случае, если break будет отсутствовать, то выполнение пойдет дальше по следующим блокам case и остальные проверки будут игнорироваться.

Таким образом видно, что у случае поочередной проверки значения в блоке case, выполнение закончится на первом истинном условии.

Группировка case

В некоторых случаях для удобства блоки case можно группировать. Модифицируем верхний пример кода:

let a = 2 + 2;

switch (a) {
  case 4:
      console.log('Точно');
      break;
  case 3: // группируем case 3 и 5
  case 5:
      console.log('Неправильно');
      break;

  default:
      console.log('Нет таких значений');
}

Таким образом варианты 3 и 5 будут выводить одно значение.

Функции

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

Объявление функции (function declaration)

Для того, чтобы использовать функцию ее следует объявить. Объявление функции происходит с помощью специального слова function.

function имя(параметры) {
  ...тело функции...
}

Функция не обязательно должна принимать какие-то параметры. Если объявляемая функция не принимает параметры, тогда используются пустые скобки.

function showMessage () {
  console.log('Hello from function');
}

Для вызова функции используется такая конструкция:

showMessage();

Локальные переменные

Локальными переменными называются те, которые объявляются внутри функций. Они не будут доступны вне ее. Это называется областью видимости.

Рассмотрим пример:

function showMessage () {
  let message = 'Hello from function';
  console.log(message);
}

showMessage(); // отобразит в консоли "Hello from function"

console.log(message); // будет ошибка, так как мы обращаемся к переменной вне области видимости, то есть локальной переменной функции showMessage за пределами которой переменной message не существует.

Внешние переменные

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

Рассмотрим на примерах.

let userName = 'Вася';

function showMessage() {
  userName = 'Петя'; // заменяем значение внешней переменной
  
  let message = 'Привет, ' + userName;
  console.log(message);
}

console.log(message); // Вася, так как функцию еще не вызвали
showMessage(); 
console.log(message); // Петя, значение внешней переменной было изменено функцией

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

function sayHello() {
  let userName = 'Костя'; // объявляем локальную переменную
  
  let message = 'Привет, ' + userName; // Петя
  console.log(message);
}

showMessage(); 
console.log(userName); // Петя, функция не трогала внешнюю переменную

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

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

function showMessage (from, text) {
  from = '*' + from + '*'; // немного украсим имя
  console.log(from + ': ' + text);
}

let from = 'Аня';
showMessage(from, 'Привет'); // *Аня*: Привет

console.log(from); // Значение from осталось прежним, так как функция изменила значение локальной переменной

Параметры по умолчанию

Если при вызове функции один из параметров не указан, его значение становится undefined.

Например:

function showMessage (from, text) {
  console.log(from + ': ' + text);
}

showMessage('Аня'); // Аня: undefined

Чтобы задать параметр по умолчанию (то есть то, что отобразиться в случае его отсутствия при вызове функции), следует его указать после знака = в объявлении функции.

Например:

function showMessage (from, text = 'Текст не добавлен') {
  console.log(from + ': ' + text);
}

showMessage('Аня'); // Аня: Текст не добавлен

Возврат значения

Вызванная функция может вернуть результат, который будет передан в вызвавший ее код.

Например:

function sum(a, b) {
  return a + b;
}

let result = sum(1,2);
console.log(result);

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

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

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

function checkAge (age) {
  if (age > 18) {
    return true;
  } else {
    return confirm('А родители разрешили?');
  }
}

let age = +prompt('Сколько вам лет?', 18);
if (checkAge(age)) {
  console.log('Доступ получен');
}

Выбор имени функции

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

  • getAge — возвращает возраст
  • calcSum — рассчитывает сумму
  • createForm — создает форму

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

Функциональные выражения (function expression)

Мы можем создать функцию и присвоить ее переменной:

let sayHi = function() {
  console.log('Привет');
};

sayHi(); // вызов функции происходит с использованием имени переменной.

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

Функции можно вызывать до ее объявления:

sayHello();

function sayHello() {
  console.log('Привет');
}

Функции стрелки

Существует бетой и коротки способ объявления функций, который часто лучше, чем обычный синтаксис.

Можно объявить функцию обычным способом:

let func = function(arg1, arg2) {
  return expression;
}

А можно с помощью синтаксиса функций-стрелок:

let func = (arg1, arg2) => expression;

Рассмотрим на конкретных примерах. Так будет выглядеть обычное объявление:

let sum = function(a, b) {
  return a + b;
}

А так объявление с помощью функции-стрелки:

let sum = (a, b) => a + b;

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

let double = n => n * 2;

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

let sayHi = () => console.log('Hi!');

Многострочные функции стрелки

В примерах выше аргументы были расположены слева от =>, а справа вычислялось выражение с их значениями.

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

let sum = (a, b) => {
  let result = a + b;
  return result;
}