Замыкания js
Объект LexicalEnvironment
Javascript
function sayHi(name){
// LexicalEnvironment = { name: 'Vasya', phrase: undefined }
// локальные переменные являются свойствами специального объекта - LexicalEnvironment
var phrase = 'Hello' + name;
// LexicalEnvironment = { name: 'Vasya', phrase: 'Hello ...' }
alert(phrase);
}
//sayHi('Vasya');
// объект LexicalEnvironment создается при вызове функции
// когда функция заканчивается обычно LexicalEnvironment "выбрасывается", потому что
// больше не нужен - память при этом освобождается
свойство [[Scope]]
Javascript
//Функция может использовать переменные, которые объявлены вне ее
var b = 2;
function f(a) {
// f.[[Scope]] = window
// Когда функция объявляется (создается), то функция объявляется в каком-то контексте
// в данном случае в глобальном объекте window
// свойство объекта функции f.[[Scope]] записывается ссылка на window
// свойство [[Scope]] объявляется 1 раз в момент СОЗДАНИЯ функции.
// Это свойство играет важную роль в поиске переменных:
// то есть переменная изначально ищется в LexicalEnvironment, а затем по ссылке
// на внешнее окружение и ее значение ставится по Scope функции
// LexicalEnvironment = { a: 1 } -> window
// Объекту LexicalEnvironment добавляется ссылка на внешнее окружение и
// ее значение ставится по Scope функции, в данном случае window
alert(a + b);
}
//f(1);
// За счет чего функции удается получить доступ к переменной, которая в ней не объявлна?
// В js существует скрытое свойство [[Scope]]
Вложенные функции
Javascript
function sayHi(name, age){
// function Declaraton обрабатываются в момент входа, при создании LexicalEnvironment.
// function expression обрабатываются в момент, когда код выполнения до них доберется
// (при создании LexicalEnvironment function expression равны undefined).
// затем после выполнени функции (sayHi) обе эти функции будет уничтожены вместе
// с объектом переменных (LexicalEnvironment) и память будет очистена
// НО БЫВАЮТ СИТУАЦИИ, КОГДА ОБЪЕКТ ПЕРЕМЕННЫХ (LexicalEnvironment) НЕ УНИЧТОЖАЕТМЯ (*)
alert(makePhrase(name));
// ----------------
function makePhrase() {
return chooseWord() + ', ' + name;
}
function chooseWord() {
return age > 18 ? 'Здравствуйте' : 'Привет';
}
}
sayHi('Петька', 18);
sayHi('Василий Иванович', 35);
ЗАМЫКАНИЯ (*)
Javascript
// замыканием называется функция вместе со всеми переменными, которые ей доступны
// доступ к переменной, которая не находится в самой функции, а находится во внешнем объекте переменных называется
// доступом через замыкание
function sayHi(name, age){
//LexicalEnvironment = {
// name: 'Петька',
// age: 18,
// makePhrase: function
// chooseWord: function
//} -> window
// НО БЫВАЮТ СИТУАЦИИ, КОГДА ОБЪЕКТ ПЕРЕМЕННЫХ (LexicalEnvironment) НЕ УНИЧТОЖАЕТСЯ:
// ВО ВРЕМЯ ВЫПОЛНЕНИЯ СОЗДАЕТСЯ ФУНКЦИЯ И ВОЗВРАЩАЕТСЯ
// ПРИ СОЗДАНИИ ФУНКЦИЯ ПОЛУЧАЕТ [[Scope]] равный текущему объекту переменных (LexicalEnvironment)
// ТАК КАК НА ОБЪЕКТ ПЕРЕМЕННЫХ (LexicalEnvironment) ЕСТЬ ССЫЛКА, ТО ОН НЕ УНИЧТОЖАЕТСЯ
// функция, которая возвращена во внешний код, как work, ссылается через свое свойство Scope
// на LexicalEnvironment, поэтому он остается в памяти. и будет оставаться там, пока на него есть хоть одна ссылка
// LexicalEnvironment держит в памяти функция work
return function () { // [[Scope]] = LexicalEnvironment
alert(makePhrase(name));
}
// ----------------
function makePhrase() {
return chooseWord() + ', ' + name;
}
function chooseWord() {
return age > 18 ? 'Здравствуйте' : 'Привет';
}
}
// ф-я (work) выше может понадобиться, например, при вызове ф-и в будущем (при нажатии по кнопке)
// функция, которая возвращена во внешний код, как work, ссылается через свое свойство Scope
// на LexicalEnvironment, поэтому он остается в памяти. и будет оставаться там, пока на него есть хоть одна ссылка
// LexicalEnvironment держит в памяти функция work
var work = sayHi('Петька', 18);
Комментарии к статье
Огромное спасибо за статью! Только с ее помощью наконец разобрался сразу со scope, LexicalEnvironment и замыканиями. Было бы здорово еще получить информацию по VariableEnvironment.