За

Замикання у JavaScript

1 вправа

Про концепцію Замикання

Замикання - це програмний прийом у JavaScript, який дозволяє використовувати змінні із зовнішньої лексичної області видимості всередині вкладеного блоку коду. JavaScript підтримує замикання прозоро, і їх часто використовують, навіть не знаючи, що це таке.

// Top-level declarations are global-scope
const dozen = 12;

// Functions create a new function-scope and block-scope.
// Referencing the outer variable here is a closure.
function nDozen(n) {
  return dozen * n;
}

Назва замикання історично походить від λ-числення і була популяризована мовою Scheme (джерело) на позначення відкритих і закритих звʼязувань змінних функції.

Навіщо використовувати замикання в JavaScript

  1. Приватність даних / Інкапсуляція даних

    • На відміну від інших мов, станом на 2020 рік не було способу оголосити приватні змінні. Тож замикання можна використовувати, щоб ефективно імітувати приватні змінні (була пропозиція ввести позначення приватних змінних, яка, можливо, вже стала стандартом на час читання цього тексту).
    // Consider this function:
    
    const saveNumber = (number) => {
      // The saved value is unaccessible by the outer lexical scope.
      const value = number;
    
      // We can provide access to the primitive value with a function, but the original will never change
      return () => value;
    };
    
    // Attempting to set the variable outside of its lexical scope results in an error
    value = 42;
    
  2. Часткове застосування

    • Функції можуть повертати функції, і коли повернена функція використовує аргумент функції, яка її створила, це приклад використання замикання для часткового застосування. Іноді це називають каррінгом функції.
    // The arguments are applied one-by-one, using closures to arrive at the final result
    function partialBuildUri(scheme) {
      return function (domain) {
        return function (path) {
          return `${scheme}://${domain}/${path}`;
        };
      };
    }
    
    // A function could apply them all at once.
    function buildUri(scheme, domain, path) {
      return partialBuildUri(scheme)(domain)(path);
    }
    
    // Or apply a few to create a flexible system of functions for reuse.
    function buildHttpsExercismUri(path) {
      return partialBuildUri('https')('exercism.org');
    }
    

Лексична область видимості змінних

У будь-якій мові програмування замикання тісно повʼязані з областю видимості змінних. У JavaScript є 3 типи лексичної області видимості для змінних:

  1. Глобальна область видимості: сюди належать змінні, оголошені поза функціями та блоками.
  2. Область видимості функції: сюди належать змінні, оголошені всередині функції за допомогою ключового слова var.
  3. Область видимості блоку: сюди належать змінні, оголошені всередині блоку ({...}) за допомогою ключових слів let і const.

На практиці замикання часто виникає тоді, коли функція (або блок) використовує змінну із зовнішньої області видимості. У JavaScript це підтримується прозоро, тож замикання часто використовують, навіть не згадуючи про них.

Область видимості функції

Ключове слово var визначає змінну з областю видимості функції. Це означає, що змінні, визначені через var, доступні будь-де у функції, де їх визначено, і в будь-якій вкладеній лексичній області видимості (чи то функції, чи то блоку).

{
  var five = 5;
}

// This will succeed because 'five' exists in the same scope
var tenTimes = five * 10;

Область видимості блоку

Ключові слова let і const визначають змінні з областю видимості блоку. let визначає змінну, яку можна змінювати: їй можна присвоювати значення багато разів, і її можна визначити, але не ініціалізувати. const визначає змінну, яку потрібно ініціалізувати під час визначення, і після цього її значення не може змінитися. Якщо змінній const присвоєно примітивне значення, його не можна змінити. Якщо змінній const присвоєно посилальне значення, як-от масив чи обʼєкт, саме посилання змінити не можна, але вміст масиву можна змінювати.

Розгляньмо цей блок:

// 'two' is defined at the top-level, therefore available to the global-scope
const two = 2;

{
  // This succeeds, as 'two' is available from the outer lexical scope
  const oneLess = two - 1;
}

// This throws an error because oneLess is not defined outside of the previous inner lexical scope
console.log(oneLess);

Хоча фігурні дужки ({...}) можна використовувати довільно, щоб створювати блоки, найчастіше вони трапляються навколо умовних конструкцій, функцій і класів.

const PI = 3.14;

// This function uses a closure for the value of PI (π)
function areaOfCircle(radius) {
  return PI * radius * radius;
}
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці

Вивчити концепцію Замикання