Передача функций и колбэки
В прошлом уроке мы увидели, что функция в JavaScript – обычное значение. А значит её можно не только хранить в переменной, но и передать другой функции.
Зачем? Чтобы передать ей не готовое значение, а действие, которое она сможет выполнить сама.
До сих пор аргументами были числа и строки: double(5), greet('Ира'). Но иногда функции нужно передать не готовые данные, а действие, которое она должна выполнить. Поскольку функция в JavaScript – тоже значение, её можно передать аргументом:
function runTwice(action) { action(); action();}function sayHi() { console.log('Привет!');}runTwice(sayHi);В runTwice(sayHi) мы не вызываем sayHi. Мы передаём саму функцию. Внутри runTwice она оказывается в параметре action, и уже runTwice решает, когда её вызвать – в нашем случае два раза.
Если хотим передать саму функцию, пишем её имя без скобок: sayHi – функция, sayHi() – результат её вызова.
Запись runTwice(sayHi()) делает другое: сначала вызовется sayHi(), а в runTwice уйдёт результат этого вызова.
runTwice(sayHi);runTwice(sayHi());Пока мы создали sayHi отдельно, дали ей имя, а затем передали в runTwice. Это удобно, если функция понадобится ещё где-нибудь.
Но что, если это действие нужно только здесь?
Функцию можно создать прямо в аргументе
Объявлять её отдельно необязательно: Function Expression можно написать прямо там, где требуется значение:
function runTwice(action) { action(); action();}runTwice(function () { console.log('Привет!');});Здесь мы создали функцию и сразу передали её в runTwice – отдельного имени ей не понадобилось.
Колбэк
У такого приёма есть своё название. Функцию, которую передают другой функции, чтобы та могла её вызвать, называют callback, или колбэком:
function runTwice(action) { action(); action();}const sayHi = function () { console.log('Привет!');};runTwice(sayHi); // колбэк – sayHi// колбэк – функция, созданная на местеrunTwice(function () { console.log('Пока!');});В обоих вызовах переданная функция – колбэк, а runTwice – функция, которая его получает и решает, когда вызвать. Здесь оба колбэка – Function Expression: sayHi сохранена в переменной, вторая создана прямо в аргументе.
Точно так же колбэком может быть и Function Declaration:
function sayBye() { console.log('До встречи!');}runTwice(sayBye);Важно: колбэк не обязательно запускается «когда-нибудь позже». Он может быть вызван сразу, как здесь, или позже – например, после клика пользователя или завершения таймера.
Функция управляет «когда», колбэк – «что делать»
function repeat(n, action) { for (let i = 1; i <= n; i++) { action(i); }}const showStep = function (i) { console.log(`Шаг ${i}`);};repeat(3, showStep);Обратите внимание: repeat не просто вызывает action, а передаёт ему текущее значение i. Поэтому колбэк получает данные от функции, которая им управляет.
repeat знает, когда и сколько раз выполнить действие: for (let i = 1; i <= n; i++). Но она не знает, что именно делать на каждом повторении – это действие ей передают отдельно. Поэтому одну и ту же repeat можно использовать с разными функциями:
const showSquare = function (i) { console.log(i * i);};repeat(3, showSquare);Один код управляет процессом, другой определяет действие. Как вызов уходит внутрь repeat и возвращается – по шагам:
showStep.// теперь вы знаете
- Если нужно передать саму функцию, пишем её без (); со скобками функция сначала вызывается
- Функцию можно создать прямо в аргументе, если отдельное имя ей не понадобится
- Колбэк – функция, переданная другой функции, чтобы та могла её вызвать
- Колбэком может быть и Function Declaration, и Function Expression
- Принимающая функция может решать, когда вызвать колбэк, сколько раз его вызвать и какие аргументы ему передать
Что в этом вызове является колбэком?
function repeat(n, action) {for (let i = 1; i <= n; i++) {action(i);}}const showStep = function (i) {console.log(`Шаг ${i}`);};repeat(3, showStep);
Сколько раз будет вызвана sayHi?
function runIf(allowed, action) {if (allowed) {action();}}function sayHi() {console.log('Привет!');}runIf(false, sayHi);runIf(true, sayHi);
В каких вызовах в параметр action попадёт функция?
function runTwice(action) {action();action();}function sayHi() {console.log('Привет!');}
Выбери все верные варианты
В каком порядке появятся строки в консоли?
function run(action) {console.log('до');action();console.log('после');}run(function () {console.log('внутри');});
Что напечатает программа?
function withName(action) {action('Ира');}withName(function (name) {console.log('Привет, ' + name);});