Skip to content

Latest commit

 

History

History
161 lines (112 loc) · 7.64 KB

File metadata and controls

161 lines (112 loc) · 7.64 KB

Вложенные функции

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

Рассмотрим базовый пример:

function doOuterFunctionStuff(nr) {
  console.log("Outer function");
  doInnerFunctionStuff(nr);
  
  function doInnerFunctionStuff(x) {
    console.log(x + 7);
    console.log("I can access outer variables:", nr);
  }
}

doOuterFunctionStuff(2);

При выполнении этого кода мы получим:

Outer function
9
I can access outer variables: 2

Как работают вложенные функции

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

Самое интересное в этом механизме — то, что внутренняя функция имеет доступ к переменным и параметрам внешней функции. В примере выше внутренняя функция doInnerFunctionStuff имеет доступ к параметру nr внешней функции, хотя он не был явно передан внутрь.

Область видимости и вложенные функции

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

Рассмотрим пример, демонстрирующий ограничения области видимости:

function doOuterFunctionStuff(nr) {
  doInnerFunctionStuff(nr);
  
  function doInnerFunctionStuff(x) {
    let z = 10; // z объявлена внутри внутренней функции
  }
  
  console.log("Not accessible:", z); // Ошибка!
}

doOuterFunctionStuff(2);

В этом примере мы попытаемся обратиться к переменной z вне функции, где она была объявлена. Это вызовет ошибку ReferenceError, поскольку переменная z существует только внутри функции doInnerFunctionStuff.

Доступность вложенных функций

Вложенные функции не доступны извне родительской функции. Попытка вызвать вложенную функцию снаружи приведет к ошибке:

function doOuterFunctionStuff(nr) {
  doInnerFunctionStuff(nr);
  
  function doInnerFunctionStuff(x) {
    let z = 10;
  }
}

// Эта строка вызовет ошибку:
doInnerFunctionStuff(3); // ReferenceError

Мы получаем ошибку ReferenceError, потому что doInnerFunctionStuff определена только внутри области видимости функции doOuterFunctionStuff и не существует вне ее.

Практическое применение вложенных функций

Вложенные функции полезны в нескольких сценариях:

  1. Инкапсуляция логики: Когда нужно скрыть вспомогательную логику внутри основной функции
  2. Замыкания: Для создания функций, которые "запоминают" окружение, в котором были созданы
  3. Рекурсивные вспомогательные функции: Когда нужно реализовать рекурсию с дополнительными параметрами

Пример с инкапсуляцией:

function processUserData(userData) {
  validateData(userData);
  process();
  
  function validateData(data) {
    // Логика проверки данных
    if (!data.name) throw new Error("Name is required");
  }
  
  function process() {
    // Основная логика обработки
    console.log("Processing:", userData.name);
  }
}

Замыкания и вложенные функции

Одно из самых мощных применений вложенных функций — создание замыканий. Замыкание — это функция, которая запоминает внешние переменные и имеет к ним доступ даже после того, как внешняя функция завершила выполнение.

Пример замыкания:

function createCounter() {
  let count = 0;
  
  return function() {
    count++;
    return count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

В этом примере внутренняя функция "запоминает" переменную count и может изменять ее при каждом вызове, даже though функция createCounter уже завершила выполнение.

Частые ошибки и как их избежать

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

  2. Непонимание области видимости: Переменные, объявленные внутри вложенной функции, недоступны снаружи.

  3. Циклы и вложенные функции: Будьте осторожны при создании функций внутри циклов, так как они могут захватывать изменяемые переменные.

Пример проблемы с циклом:

// Неожиданное поведение:
for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i); // Всегда выводит 3
  }, 100);
}

// Решение:
for (var i = 0; i < 3; i++) {
  (function(j) {
    setTimeout(function() {
      console.log(j); // Выводит 0, 1, 2
    }, 100);
  })(i);
}

Упражнения для закрепления

  1. Создайте функцию calculate, которая принимает два числа и операцию (как строку), а внутри содержит вложенные функции для сложения, вычитания, умножения и деления.

  2. Напишите функцию createGreeter, которая принимает приветствие (например, "Hello") и возвращает функцию, которая будет принимать имя и выводить полное приветствие.

  3. Реализуйте функцию-счётчик, используя замыкания, которая может увеличивать, уменьшать значение и выводить его текущее состояние.