IIFE

IIFE (Immediately Invoked Function Expression) — функциональное выражение, которое вызывается сразу после создания. Создаёт изолированную область видимости.

Зачем нужно

IIFE позволяет создать область видимости, не загрязняя глобальное пространство имён. До появления ES-модулей и блочной области видимости (let/const) это был основной способ инкапсуляции кода в JavaScript.

Где используется

Модульный паттерн (до ES-модулей), инициализация библиотек, изоляция переменных, полифиллы, защита от конфликтов имён, скрипты на страницах.

Предпосылки

Function Expression, Замыкания (Closures), Переменные

Синтаксис

Основные формы

// Классическая форма
(function {
  console.log('IIFE выполнена');
});

// Альтернативная форма (скобки вокруг вызова)
(function {
  console.log('IIFE выполнена');
});

// Стрелочная функция
(() => {
  console.log('Arrow IIFE');
});

// С параметрами
(function(window, document) {
  // window и document — локальные алиасы
  console.log(window.location.href);
})(window, document);

Именованная IIFE

(function init() {
  console.log('Инициализация');
  // Имя init доступно для рекурсии внутри, но не снаружи
});

// init; // ReferenceError

Изоляция переменных

// Без IIFE — загрязнение глобальной области
var counter = 0;
var name = 'app';
// Эти переменные могут конфликтовать с другими скриптами

// С IIFE — всё изолировано
(function {
  var counter = 0;
  var name = 'app';
  // Эти переменные не видны снаружи
});

Модульный паттерн

const Calculator = (function {
  // Приватное состояние
  let history = ;

  // Приватная функция
  function addToHistory(operation) {
    history.push({
      operation,
      timestamp: Date.now()
    });
  }

  // Публичный API
  return {
    add(a, b) {
      const result = a + b;
      addToHistory(`${a} + ${b} = ${result}`);
      return result;
    },
    subtract(a, b) {
      const result = a - b;
      addToHistory(`${a} - ${b} = ${result}`);
      return result;
    },
    getHistory {
      return [...history];
    }
  };
});

Calculator.add(2, 3);       // 5
Calculator.subtract(10, 4); // 6
console.log(Calculator.getHistory);
// history и addToHistory недоступны извне

Расширение модуля

const MyModule = (function(module) {
  // Добавляем новый функционал к существующему модулю
  module.newFeature = function {
    return 'Новая функция';
  };

  return module;
})(MyModule || {});

Практические примеры

Инициализация приложения

(function {
  'use strict';

  const config = {
    apiUrl: 'https://api.example.com',
    timeout: 5000
  };

  function init() {
    setupEventListeners;
    loadInitialData;
    console.log('Приложение инициализировано');
  }

  function setupEventListeners() {
    document.querySelector('#btn').addEventListener('click', handleClick);
  }

  function handleClick(event) {
    console.log('Клик!');
  }

  function loadInitialData() {
    fetch(config.apiUrl).then(r => r.json()).then(console.log);
  }

  // Запуск после загрузки DOM
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init;
  }
});

Защита от конфликтов (jQuery)

// $ может быть перезаписан другой библиотекой
(function($) {
  // Здесь $ точно jQuery
  $(document).ready(function {
    $('.menu').toggle;
  });
})(jQuery);

Создание уникального ID-генератора

const generateId = (function {
  let id = 0;
  return function(prefix = 'id') {
    return `${prefix}_${++id}`;
  };
});

console.log(generateId);        // "id_1"
console.log(generateId('user'));   // "user_2"
console.log(generateId);        // "id_3"

Однократная инициализация

const database = (function {
  console.log('Подключение к БД...');
  const connection = { host: 'localhost', port: 5432 };

  return {
    query(sql) {
      console.log(`Запрос: ${sql} на ${connection.host}`);
    }
  };
}); // Подключение происходит один раз при загрузке

database.query('SELECT * FROM users');

Async IIFE

// Для использования await на верхнем уровне (до top-level await)
(async function {
  try {
    const response = await fetch('/api/data');
    const data = await response.json();
    console.log(data);
  } catch (err) {
    console.error('Ошибка:', err);
  }
});

// Стрелочная версия
(async () => {
  const data = await fetchData;
  processData(data);
});

Современные альтернативы

ES-модули

// module.js — каждый модуль имеет свою область видимости
let counter = 0;
export function increment() { return ++counter; }
export function getCount() { return counter; }
// counter изолирован автоматически

Блочная область видимости

// let/const в блоке — достаточно для изоляции
{
  const privateVar = 'скрыто';
  let mutableVar = 0;
  // ...
}
// privateVar и mutableVar не видны здесь

Когда IIFE всё ещё полезна

Ситуация IIFE нужна?
Модуль в ES-модульной системе Нет, используй ESM
Скрипт в <script> без type=module Да
Инициализация в глобальном скрипте Да
Полифилл / библиотека для <script> Да
Создание замыкания в одну строку По ситуации

Частые ошибки

1. Забытые скобки вокруг функции

// SyntaxError — JS думает, что это Function Declaration
// function { console.log('test'); };

// Правильно — оборачиваем в скобки
(function { console.log('test'); });

2. Отсутствие точки с запятой перед IIFE

const x = 42
// Без ; перед IIFE может быть ошибка
(function {})
// JS может интерпретировать как: 42(function {})

// Решение: ставить ; или начинать IIFE с ;
;(function {})

3. Возврат значения без присваивания

// Результат IIFE потерян
(function {
  return { data: 'важные данные' };
});

// Правильно — присвоить результат
const result = (function {
  return { data: 'важные данные' };
});

Практика

  1. Создай IIFE, которая объявляет приватную переменную и возвращает объект для работы с ней
  2. Реализуй модульный паттерн для корзины покупок (add, remove, getTotal)
  3. Напиши IIFE с параметрами, принимающую window и document
  4. Создай async IIFE, которая загружает данные при инициализации
  5. Перепиши IIFE-модуль на ES-модуль — сравни подходы

Связанные темы

Ресурсы


🎓 Источник: Функции, стрелочные функции, контексты, замыкания

  • 📅 2018-09-27 · YouTube · ID: pn5myCmpV2U
  • Тезисы:
    • IIFE = Immediately Invoked Function Expression
    • Объявил → вызвал → забыл ссылку
    • Раньше нужно было для изоляции контекста — сейчас достаточно блока {} с let/const
    • До ES6 IIFE использовали в цикле с var, чтобы зафиксировать значение итератора
  • Цитата: «Это было необходимо в JavaScript раньше, когда нельзя было создавать контексты при помощи скобочек.»