Замыкание (Closure)

Что такое замыкание?
Где применяется замыкание?
Что означает лексическая области видимости функции?

При выполнении функции используется та область видимости (Scope) переменных которая существовала при объявлении этой функции - лексическая область видимости.

Пример:

var func = function(){
    var i = 10;
    return function(){
        return i;
    };
};

var anotherFunc = function(){
    var i = 20;
    console.log(func()());
};

anotherFunc(); // в консоле будет 10, т.к. у внут функции func - лексическая область видимости внутри функции func

Замыкание - это особый объект который сочетает в себе две вещи: функцию и окружение, в которой функция была создана.
У нас есть внешняя функция у которой объявлена переменная, и есть внутряняя функция которая использует эту переменную. Говорят что внутряняя функция замыкает в себе переменную внешней функции. Она не дает удалить эту переменную сборщиком мусора, даже когда внешняя функция отработала и была удалена.

Closure;

Пример использования замыкания:

function counter(){
    var count = 0; // это не внутренее свойства, а просто ссылка на область в памяти.

    return {
        next: function(){
            console.log(++count);
        }
    }
}

var c = counter();
c.next(); //1
c.next(); //2

Что происходит на самом деле. При выполнении функции создается объект LexicalEnvironment (функция тоже на самом деле объект, который можно возвращать, присваивать, передавать как параметр), который хранит все свойства и агрументы функции. Также он получает скрытое свойство [[Scope]] (next.[[Scope]] = counter), которое ссылается на лексическое окружение в котором была вызвана функция. И при поиске свойства - сначало оно ищется внутри своего объекта, потом по ссылке [[Scope]] во внешнем окружении, и т.д.

Closure function

С помощью замыкания мы можем реализовать инкапсуляцию (скрытие внутренней реализации):

function counter(){
    var count = 0;

    return {
        get: function(){
            return count;
        },
        set: function(c){
            count = c;
        }
    }
};
var myCounter = counter();
console.log(myCounter.count); // undefined, нельзя обратится напрямую к переменной функции
myCounter.set(10);
console.log(myCounter.get()); //10

Еще распространенная ошибка это замыкание и циклы:

var arr = [];
for(var i = 0; i < 3; i++){
    arr[i] = function(){
        console.log(i);
    };
}

arr[0](); //мы получим 3, а не 0

Было создано три замыкания, но все они были созданы с одним и тем же контекстом исполнения (окружением). К моменту выполнения функции цикл уже давно отработал, а значит переменная i (одна и та же для всех трех замыканий) указывает на последний элемент массива (3).

Методы решения:
Метод 1

var arr = [];
for(let i = 0; i < 3; i++){
    arr[i] = function(){
        console.log(i);
    };
}

arr[0](); //мы получим 3, а не 0

Метод 2

var arr = [];
for(var i = 0; i < 3; i++){
    (function(j){
        arr[j] = function(){
            console.log(j);
        };
    })(i);
}

arr[0](); //мы получим 3, а не 0

Метод 3

//todo

Материал взят из GetInstance - use strick

results matching ""

    No results matching ""