Функция — это мини-программа внутри основной программы, которая делает какую-то понятную и полезную вещь, например проверяет, что вы ввели правильный электронный адрес. Чтобы эта мини-программа заработала, нужно сделать три вещи: написать эту программу, дать ей имя, а потом вызвать — то есть обратиться к ней по имени.
Но бывают такие функции, которые срабатывают сами, даже если к ним никто не обращался. Это называется самовызывающейся функцией. Вы наверняка встретите такие функции, когда будете брать чужой код на StackOverflow. Рассказываем, как это работает, как этим пользоваться и в чём хитрость.
Как работает обычная функция
Чаще всего функции в коде работают так: они получают в работу какие-то данные, что-то с ними делают и отдают результат. Вот как это происходит:
- Программист создаёт новую функцию и даёт ей название.
- Внутри этой функции пишется код — он не участвует в работе основной программы, а нужен только для этой функции. Получается изолированная программа внутри программы.
- Когда в основной программе встречается название функции, компьютер идёт в неё, выполняет код оттуда и возвращается обратно в программу.
В коде это выглядит так:
// объявляем функцию с именем s
function kakoeToNazvanie() {
// тут идут внутренние команды функции
// готовим приветствие
var text = 'Привет, это журнал «Код»!';
// и выводим его
console.log(text);
}
// код основной программы
// …
// вызываем функцию s()
kakoeToNazvanie();
// на экране появилось приветствие — это мы запустили функцию, которая вывела текст
Получается, что для запуска функции нужно указать её имя как команду — это называется «вызывать функцию». Без этого компьютер не поймёт, что нужно выполнить код, который написан в этой мини-программе. Если в коде не вызвать функцию, то она так и останется без дела.
Что такое самовызывающаяся функция
Разработчики придумали в JavaScript самовызывающиеся, или немедленно срабатывающие, функции. Они называются IIFE (immediately invoked function expression) и применяются там, где функция должна сработать сразу же, как её увидел компьютер. Например, если нам нужно, чтобы скрипт сработал на странице как можно раньше, его можно обернуть в такую функцию. В этом случае браузер не будет ждать, пока загрузится вся страница, а выполнит функцию, как только дойдёт до неё при проверке скрипта.
Ещё вариант — когда нужно выполнить что-то один раз точно, а дальше как пойдёт. Здесь браузер во время загрузки скрипта выполнит эту функцию, а дальше будет выполнять код как обычно. Это может пригодиться для настройки связи с сервером, пока грузится основная часть сайта: мы не тратим время на полную загрузку, а сразу запускаем синхронизацию.
Также IIFE используют для того, чтобы защитить переменные и вложенные функции от изменений и неправильного использования. Дело в том, что все переменные и функции, созданные внутри самовызывающейся функции, доступны только внутри неё — это позволяет создавать, например, геттеры и сеттеры без использования ООП. Пример кода будет ниже.
Чтобы было понятнее про приватный и публичный доступы к свойствам и функциям, почитайте наш разбор про приватность в ООП.
Как это выглядит в коде
Есть много способов объявить самовызывающуюся функцию. Самый простой — обернуть безымянную функцию в скобки и добавить вторую пару скобок после неё:
(function(){
console.log("Привет мир");
})();
Если этот код вставить в браузер, то он сразу выполнит эту функцию и выведет приветствие на экран:
Закрывающую скобку можно перенести и в самый конец объявления функции — и она тоже будет запускаться автоматически:
(function(){
console.log("Привет мир");
}());
Также вместо первой пары скобок можно поставить знаки !,~,+,- — они тоже превратят такую функцию в самовызывающуюся:
~function(){
console.log("Привет мир");
}();
Защита переменной через самовызов
А вот как самовызывающиеся функции используются для защиты переменных в коде. Идея в том, чтобы создать некую безопасную среду, внутри которой можно будет работать с какой-то переменной, а записать в неё что-то извне — уже нельзя.
Запустите код в браузере и посмотрите, получится изменить значение внутренней переменной или нет:
// в переменной будет самовызывающаяся функция
let counter = (function () {
// внутренняя переменная, к которой есть доступ только изнутри этой функции
let i = 0;
// результат работы функции
return {
// в ответ на свойство get отдаём значение переменной i
get: function () {
return i;
},
// устанавливаем новое значение переменной
set: function (val) {
i = val;
},
// увеличиваем его на единицу
increment: function () {
return ++i;
}
};
})();
// смотрим, что в переменной i на старте, должно быть 0
console.log(counter.get());
// записываем в неё значение 3
console.log(counter.set(3));
// увеличиваем значение i на единицу, должно быть 4
console.log(counter.increment());
// пробуем записать значение напрямую, но это не сработает — у нас нет доступа к этой переменной напрямую
counter.i = 10;
// выводим текущее состояние
console.log(counter.get());
Что дальше
В следующий раз проверим работу этих функций в деле: добавим их в рабочий проект и посмотрим, какую пользу они нам там принесут.