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

Функции - это инструмент для структурирования больших программ, уменьшения повторений и изолирования кода.
2. Функциональное выражение
Функциональное выражение (function expression) — обычное объявление переменной, значение которой будет функция.
Объявим переменную add
, и присвоим ей функцию, принимающую 3 значения и возвращающую результат сложения этих значений.
Имя функции - это действие, глагол начинающийся с маленькой буквы, отвечающий на вопрос 'Что сделать?'
. Например: findSmallesNumber
, fetchUserInfo
, validateInput
.
const add = function (a, b, c) {
return a + b + c;
};
Copy
Определение функции начинается с ключевого слова function
, за которым может следовать необязательное имя функции. В круглых скобках идут параметры — перечисление данных, которые функция будет получать из вне. Параметров может быть несколько или вообще ни одного, тогда записываются просто пустые круглые скобки ()
.
Далее идет тело функции, заключенное в фигурные скобки {}
, содержащее инструкции, которые необходимо выполнить при вызове функции. Тело функции всегда заключают в фигурные скобки, даже если оно состоит из одной инструкции.
Оператор return
определяет возвращаемое значение. Когда интерпретатор доходит до return
, он сразу же выходит из функции, и возвращает это значение в то место кода, где функция была вызвана.
Оператор return
без выражения возвращает значение undefined
. При отсутствии return
в теле функции, она все равно вернет значение undefined
.
Затем, когда необходимо, функция вызывается с помощью имени и круглых скобок, внутри которых могут быть переданы аргументы.
Термин аргументы используется при вызове функции, когда мы передаем значения в функцию.
Термин параметры используется при объявлении функции, это те локальные переменные внутри функции, в которые будут записаны значения аргументов во время ее вызова.
В JavaScript важен порядок объявления параметров функции. Не существует никакого другого механизма пояснить интерпретатору как значения аргументов функции при вызове связаны с параметрами.
Порядок объявления параметров соответствует порядку передачи аргументов при вызове функции: значение первого аргумента будет присвоено первому параметру, второго аргумента - второму параметру и т. д. Если параметров будет меньше чем аргументов, то параметрам без значений будет присвоено undefined
.
// a, b, c это параметры
const add = function (a, b, c) {
return a + b + c;
};
// 1, 2, 3 это аргументы
const result = add(1, 2, 3);
console.log(result); // 6
// 5, 10, 15 это аргументы
console.log(add(5, 10, 15)); // 30
Copy
Функция может либо вызвать побочные эффекты (изменять глобальные переменные), либо возвращать результат своей работы. В зависимости от того, какой фрагмент кода будет помещен внутри функции, произойдет либо возврат вычисленного значения, либо изменение состояния программы, а иногда и оба действия.
3. Порядок выполнения кода
Если при выполнении кода, интерпретатор встречает вызов функции, он приостанавливает выполнение текущего кода и начинает выполнять код из тела функции. После того как весь код функции будет выполнен, интерпретатор выходит из тела функции, возвращаясь в то место, откуда пришел и продолжает выполнять код, следующий ниже вызова функции.
const fnA = function () {
console.log('Начала выполняться [fnA]');
fnB();
console.log('Продолжила выполняться [fnA] после выхода из [fnB]');
};
const fnB = function () {
console.log('Выполняется [fnB]');
};
console.log('Начал выполнение [main]');
fnA();
console.log('Продолжил выполняться [main] после выхода из [fnA]');
/*
* Начал выполнение [main]
* Начала выполняться [fnA]
* Выполняется [fnB]
* Продолжила выполняться [fnA] после выхода из [fnB]
* Продолжил выполняться [main] после выхода из [fnA]
*/
Copy
Пошагово разберем выполнение кода примера:
При входе в js-файл, код начинает выполняться сверху вниз.
Вызов
fnA()
заставляет интерпретатор приостановить исполнение кода и зайти в тело функцииfnA
.В функции
fnA
интерпретатор встречает вызов функцииfnB
, которая перехватывает контроль и исполняется.Как только интерпретатор выполнил функцию
fnB
, то есть в ней произошелreturn
, в нашем случае не явный, интерпретатор возвращается в функциюfnA
и продолжает выполнять ее с того места где остановился.Как только интерпретатор выполнил функцию
fnA
, то есть в ней произошелreturn
, в нашем случае не явный, интерпретатор возвращается в глобальный код и продолжает его выполнение.
4. Параметры по умолчанию
При вызове функции необязательно указывать значения всех аргументов, которые перечислены в параметрах функции. Но иногда параметрам, которым не передали значение через аргумент бывает необходимо присвоить какое-то значение, отличное от undefined
.
Новые возможности ES6 позволяют сделать это очень простым и очевидным образом, указывая значение по умолчанию прямо при объявлении параметров в подписи функции. При такой записи, если значение переданного аргумента равно undefined
, в параметр записывается значение по умолчанию.
const count = function (countFrom = 0, countTo = 10, step = 1) {
console.log(`countFrom = ${countFrom}, countTo = ${countTo}, step = ${step}`);
for (let i = countFrom; i <= countTo; i += step) {
console.log(i);
}
};
count(1, 5); // countFrom = 1, countTo = 5, step = 1
count(2); // countFrom = 2, countTo = 10, step = 1
count(undefined, 5, 2); // countFrom = 0, countTo = 5, step = 2
count(); // countFrom = 0, countTo = 10, step = 1
Copy
5. Псевдомассив arguments
Доступ к набору всех аргументов можно получить через специальную локальную переменную arguments
, которая доступна только внутри функции и хранит все аргументы как псевдомассив.
Псевдомассив — коллекция, имеющая свойство length
и возможность обратиться к элементу по индексу, но отсутствием большинства методов для работы с массивом.
Псевдомассив arguments
содержит список аргументов, переданных функции при вызове, но количество переданных аргументов может не совпадать с количеством объявленных параметров и это не приведет к ошибке.
Рассмотрим пример использования arguments
в функции, которая суммирует любое количество аргументов:
const sum = function () {
let total = 0;
for (const argument of arguments) {
total += argument;
}
return total;
};
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4)); // 10
console.log(sum(1, 2, 3, 4, 5)); // 15
Copy
5.1. Способы преобразования псевдомассив
Так как у псевдомассив нет методов типа slice()
или includes()
, часто необходимо преобразовать его в полноценный массив. На практике используют несколько основных способов преобразования.
Используя метод Array.from()
, который создаст массив из итерируемого объекта.
const fn = function () {
// В переменной args будет полноценный массив
const args = Array.from(arguments);
};
Copy
Используя операцию ...
(rest), она позволяет собрать произвольное количество элементов, в нашем случае аргументов, в массив и сохранить его в переменную. Собираем все аргументы используя операцию rest
прямо в подписи функции.
const fn = function (...args) {
// В переменной args будет полноценный массив
};
Copy
6. Паттерн Guard Clause
Оператор if...else
- это основной способ создания логических деревьев. Тем не менее, сложные вложенные ветвления делают код более запутанным и трудным для понимания.
Создадим функцию, которая обрабатывает снятие денег с личного счета в банке. Функция получает сумму для снятия и текущий баланс счета, после чего, в зависимости от условия, выполняет тот или иной блок кода.
const withdraw = function (amount, balance) {
if (amount === 0) {
console.log('Для проведения операции введите сумму больше нуля.');
} else if (amount > balance) {
console.log('Недостаточно средств на счету.');
} else {
console.log('Операция снятия средств проведена.');
}
};
withdraw(0, 300); // Для проведения операции введите сумму больше нуля.
withdraw(500, 300); // Недостаточно средств на счету.
withdraw(100, 300); // Операция снятия средств проведена.
Copy
Даже в таком простом примере есть группа вложенных условных операторов, среди которых не сразу можно выделить нормальный ход выполнения кода из-за особенности синтаксиса if...else
.
Паттерн guard clause - это способ использовать возможность досрочного возврата из функции с помощью оператора return
, чтобы сделать вложенные условные выражения более одномерными.
Выделим все проверки условий в отдельные операторы if
, после чего добавим код, идущий в теле else
. В идеальном случае, должен получиться плоский список условных операторов, идущих один за другим, а в конце блок, который выполнится только в том случае, если не выполнится ни один if
.
const withdraw = function (amount, balance) {
/*
* Проверяется условие. Если оно выполняется, происходит
* console.log и выход из функции. Код идущий после тела if
* не выполнится.
*/
if (amount === 0) {
console.log('Для проведения операции введите сумму больше нуля.');
return;
}
/*
* Если условие первого if не выполнилось, его тело пропускается
* и интерпретатор доходит до этого if.
* Проверяется условие. Если оно выполняется, происходит
* console.log и выход из функции. Код идущий после тела if
* не выполнится.
*/
if (amount > balance) {
console.log('Недостаточно средств на счету.');
return;
}
/*
* Если ни один из предыдущих if не выполнился,
* интерпретатор доходит до этого кода и выполняет его.
*/
console.log('Операция снятия средств проведена.');
};
withdraw(0, 300); // Для проведения операции введите сумму больше нуля.
withdraw(500, 300); // Недостаточно средств на счету.
withdraw(100, 300); // Операция снятия средств проведена.
Copy
Используя такой подход, получаем более чистый, плоский и понятный код, который легче рефакторить.
7. Объявление функции
Другой способ создать функцию — использовать ключевое слово function
в начале инструкции. Такая запись называется объявление функции (function declaration).
Инструкция определяет переменную add
и присваивает ей заданную функцию. Эта форма записи не требует обязательной точки с запятой после закрытия фигурной скобки тела функции.
function add(a, b, c) {
return a + b + c;
}
Copy
Особенностью этого синтаксиса является то, что функцию можно вызвать до ее объявления в коде. Это может быть удобно, потому что не нужно беспокоиться о необходимости определять все функции выше того места, где они используются. Механизм поднятия идентификаторов описан тут.
add(1, 2, 3); // 6
print('text'); // text
function add(a, b, c) {
return a + b + c;
}
function print(str) {
console.log(str);
}
Copy
С другой стороны, при таком синтаксисе может быть сложно отследить связь между местом объявления функции и местом ее вызова. Современные гайды по стилю кода, составленные большими компаниями с многолетним опытом разработки, так же склоняются к использованию функциональных выражений. Поэтому рекомендуется использовать функциональные выражения, вместо объявлений функции.
// ❌ Плохо
function fn() {}
// ✅ Хорошо
const fn = function () {};
8.Стрелочные функции
Стрелочные функции имеют сокращенный, более лаконичный синтаксис и некоторые особенности. Подобно функциональным выражениям, они присваиваются переменным или могут быть анонимными. Их использование очень удобно и значительно сокращает объемы кода, особенно когда функция маленькая.
Все стрелки создаются с помощью функционального выражения, если функция не анонимна, то она должна быть присвоена переменной. Поэтому следует помнить, что перед использованием стрелочной функции её всегда необходимо создать заранее.
// Обычное функциональное выражение
const add = function (a, b, c) {
return a + b + c;
};
// Тоже самое записано как стрелочная функция
const add = (a, b, c) => a + b + c;
Copy
Слово function
не используется, вместо этого сразу идет объявление параметров, за которыми всегда следует символ =>
.
// Если параметров несколько, то они перечисляются через запятую в круглых скобках.
const fn = (a, b, c) => {
return a + b + c;
};
// Если параметр один, то он может быть без круглых скобок.
const fn = x => {
return x * 2;
};
// Если параметров нет, то обязательно должны быть пустые круглые скобки.
const fn = () => {
console.log('Hello! :]');
};
Copy
После =>
идет тело функции. Здесь может быть два варианта: с фигурными скобками или без них.
/*
* Если фигурные скобки после => есть, значит необходимо явно указать то,
* что должна вернуть функция - поставить return и выражение.
* Это называется явный возврат (explicit return)
*/
const fn = (a, b, c) => {
return a + b + c;
};
/*
* Если фигурных скобок нет, то возвращается результат выражения стоящего после =>
* Это называется неявный возврат (implicit return)
* В примере ниже вернется результат выражения сложения a, b и c
*/
const fn = (a, b, c) => a + b + c;
Copy
9. Стрелочные функции и arguments
У стрелочных функций нет локальной переменной arguments
, содержащей все аргументы. Если необходимо собрать все аргументы в массив, используется операция rest
.
const add = (...args) => {
console.log(args);
};
add(1, 2, 3); // [1, 2, 3]
Last updated