меню

Замыкания в JavaScript используются довольно часто, и вы, наверняка, уже сталкивались с ними. Они позволяют делать код более выразительным и лаконичным. В какой-то степени, замыкания могут показаться сложной темой, но в данной статье мы постараемся разобраться с ними. Перед знакомством с этой темой необходимо хорошо понимать, какие особенности имеет область видимости переменных в JavaScript.

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

Замыкание — это функция, объявленная внутри другой функции и имеющая доступ к переменным внешней (вмещающей) функции. Замыкание имеет доступ сразу к трем областям видимости:

  • к своей собственной области видимости (переменные, объявленные внутри замыкания);
  • к области видимости внешней функции (переменные, объявленные внутри внешней функции);
  • к глобальной области видимости.

Внутренняя функция имеет доступ не только к переменным внешней функции, но и к параметрам внешней функции. Обратите внимание, что внутренняя функция не может использовать объект arguments внешней функции, однако, имеет доступ к параметрам внешней функции напрямую.

Простыми словами замыкание — это функция, описанная внутри другой функции.

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

  
function showName(firstName, lastName) { 
    var nameIntro = "Your name is ";

    function makeFullName() {
        return nameIntro + firstName + " " + lastName;
    }

    return makeFullName();
}

showName("Michael", "Jackson"); // Your name is Michael Jackson
 

Замыкания также нередко используются в jQuery:

 
$(function() {
    var selections = []; 
    $('.niners').click(function() {
        selections.push(this.prop('name'));
    });
});
 

Правила и побочные эффекты замыканий

Замыкание имеет доступ к переменным внешней функции даже после ее выполнения.

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

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

Замыкания хранят ссылки на переменные внешней функции, а не фактические значения.

Такая интересная особенность позволяет описывать приватные переменные. Это способ впервые был предложен Дугласом Крокфордом:

 
function user() {
    var name = 'Unknown';
    return {
        getName: function() {
            return name;
        },
        setName: function(newName) {
            name = newName;
        }
    }
}

var testUser = user();
testUser.getName(); // Unknown
testUser.setName('John Smith'); // Изменяем значение приватной переменной
testUser.getName(); // John Smith
 

Побочные эффекты, связанные с замыканиями

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

 
function userIdGenerator(users) {
    var i;
    var uniqueId = 100;

    for (i = 0; i < users.length; i++) {
        users[i]['id'] = function()  {
            return uniqueId + i;
        }
    }

    return users;
}

var testUsers = [{ name: "Smith", id:0 }, { name: "Johnson", id:0 }, { name: "Thompson", id:0 }];
var testUsersIds = userIdGenerator(testUsers);
var firstId = testUsersIds[0];
console.log(firstId.id()); // 103
 

В предыдущем примере, к тому времени, когда вызывается анонимная функция, значение i становится равно 3 (длина массива). Число 3 было прибавлено к значению переменной uniqueId, тем самым для всех элементов массива testUsers значение id стало равно 103, вместо предполагаемых 100, 101, 102.

Решением предыдущей проблемы может быть шаблон немедленно вызываемой функции (Immediately Invoked Function Expression — IIFE):

 
function userIdGenerator(users) {
    var i;
    var uniqueId = 100;

    for (i = 0; i < users.length; i++) {
        users[i]['id'] = function(j) {
            return function() {
                return uniqueId + j;
            } ();
        } (i);
    }

    return users;
}

var testUsers = [{ name: "Smith", id:0 }, { name: "Johnson", id:0 }, { name: "Thompson", id:0 }];
var testUsersIds = userIdGenerator(testUsers);

var firstId = testUsersIds[0];
console.log(firstId.id); // 100

var secondId = testUsersIds[1];
console.log(secondId.id); // 101
 

Заключение

Замыкания — это очень интересный и крайне полезный прием программирования. Суть замыкания можно выразить так: в функции доступны все переменные той области видимости, в которой она была определена.

Замыкания позволяют реализовывать аналог приватных переменных, минимизировать выход переменных в глобальную область видимости. С другой стороны, неаккуратное использование замыканий может привести к побочным эффектам, описанным выше. Поэтому использовать их стоит крайне внимательно.


Возможно, вам будет интересно

Youtube несколько видео на странице и стоп проигрывания предыдущего видео.

Youtube несколько видео на странице. Как сделать остановку предыдущего видео, при запуске следующего? На сайте расположено на одной странице три видео. При включении нужно чтобы другое видео, если запущено , останавливалось. Как это реализовать?

JavaScript - отслеживание изменения ориентации на мобильных устройствах

Если Ваше мобильное приложение поддерживает только портретную или только горизонтальную ориентацию, то есть большая вероятность того, что некоторые элементы придётся менять, в зависимости от положения устройства.

Склонение окончаний в словах на Javascript

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

Как проверить с помощью jQuery и Javascript состояние checkbox

Часто возникает ситуация, что на HTML-странице имеется переключатель (checkbox).

Оформление заявки

Документы на создание сайта

Изучите наше коммерческое предложение, заполните БРИФ и отправьте его на почту maxidebox@list.ru. Изучив все пожелания из БРИФ-а, обратным ответом оповестим Вас по стоимости разработке, ответим на вопросы.

КП на создание сайта Коммерческое предложение на созданеи сайта

Мы берем на себя ответственность за все стадии работы и полностью избавляем клиентов от забот и необходимости вникать в тонкости.

Скачать БРИФ (акета) на создание сайта Скачать БРИФ (акета) на создание сайта

Зополните у БРИФ-а все необходимые поля. Сделайте краткое описание к каждому из пунктов анкеты, привидите примеры в соответсвующий пунктах - это позволит лучше понять Ваши ожидания и требования к сайту