меню

Замыкания в 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
 

Заключение

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

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


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

Javascript array шпаргалка

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

Объекты в JavaScript

В статье рассмотрены базовые понятия, связанные с объектами в JavaScript: определение объектов, создание объектов, базовые операции с объектами

Как исправить ошибку «RangeError: Invalid time value» при вызове метода toISOString даты JavaScript?

В этой статье мы рассмотрим, как исправить ошибку «RangeError: Invalid time value» при вызове toISOString метода даты JavaScript.

Видео самоучитель jQuery от Envato

Видео курс от компании Envato, Видео курс на английском языке. jQuery - это библиотека, которая значительно упрощает и ускоряет написание JavaScript кода. Видео курс самоучителя jQuery позволит Вам научится работать на нем. Пройдя данный курс Вы научитесь основам работы с jQuery!

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

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

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

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

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

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

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