Главная Категории Контакты Поиск

Введение в замыкание. Closure

Что такое замыкание.

JavaScript·12.12.2019·читать 2 мин 🤓·Автор: Alexey Myzgin

Замыкание

Замыкание обеспечивает доступ к переменным в своей лексической области; включая переменные родителей, которые были удалены из стека вызовов, путём определения, какие именно переменные понадобятся дочерним функциям, путём сохранения их в памяти.

Другими словами, замыкание даёт нам доступ к области видимости внешней функции из внутренней функции. В JavaScript замыкания создаются каждый раз, когда во время создания функции, внутри неё создаётся ещё одна функция.

Инкапсуляция

Инкапсуляция позволяет нам скрывать/показывать свойства функций и объектов.

Замыкания обычно используются для обеспечения конфиденциальности данных объектов. Конфиденциальность данных - это важное свойство, которое помогает нам программировать интерфейс, а не реализацию. Дання концепция важна тем, что помогает нам создавать более надежное программное обеспечение.

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

Замыкания подобны объектам в том смысле, что они представляют собой механизм для хранения состояния:

Например, в приведенном ниже примере, мы не хотим показывать функцию launch для её вызова, а также не даём доступ к timeWithoutDesctruction:

const makeNuclearButton = () => {
  // Переменные, опредёленные в области действия фабрики или конструктора
  // являются приватным для этой функции.
  // К ним нет доступа, если только мы не вернем их в качестве свойств объекта.

  let timeWithoutDesctruction = 0;
  const passTime = () => timeWithoutDesctruction++;

  // totalPeaceTime является привилегированной, так как она определена в области замыкания -
  // поэтому у неё есть доступ к timeWithoutDesctruction
  const totalPeaceTime = () => timeWithoutDesctruction;

  const launch = () => {
    timeWithoutDesctruction = -1;
    return '💥'
  }

  setInterval(passTime, 1000);
  return {totalPeaceTime};
}

const button = makeNuclearButton();
button // {totalPeaceTime: ƒ}
button.totalPeaceTime(); // 1

Таким образом, мы скрываем данные объекта, которые не должны быть напрямую доступны. Вместо прямого доступа к данным нужно вызывать методы.

Эффективное использование памяти

Замыкания эффективны с точки зрения памяти. Используя замыкания, мы можем создать переменные, которые будут храниться в памяти и использоваться в будущем.

const closureTest1 = function() {
  const bigArray = new Array(7000).fill('1');
  console.log('created');

  return function(index) {
    return bigArray[index];
  }
}

const closureTest1Fn = closureTest1();
closureTest1Fn(500);
closureTest1Fn(300);
closureTest1Fn(100);

created // from console.log('created');
// returned "1"

Или

// IIFE (Immediately Invoked Function Expression)
const closureTest2 = (function() {
  const bigArray = new Array(7000).fill('1');
  console.log('created');

  return function(index) {
    return bigArray[index];
  }
})();


closureTest2(500);
closureTest2(300);
closureTest2(100);

created // from console.log('created');
// returned "1"

Мы вызываем функцию closureTest1Fn и closureTest2 3 раза, но console.log выводится только один раз. Это происходит потому, что мы, благодаря замыканию, сохраняем в памяти значения bigArray и console.log.

Типичный случай без замыкания приведет к неэффективному использованию памяти: переменная bigArray будет создаваться и сохраняться каждый раз.

function closureTest(index) {
  const bigArray = new Array(7000).fill('1');
  console.log('created');

  return bigArray[index];
};


closureTest(500);
closureTest(300);
closureTest(100);

created // from console.log('created');
created // from console.log('created');
created // from console.log('created');
// returned "1"

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

Website, name & logo
Copyright © 2022. Alex Myzgin