Замыкание Flashcards
Замыкание
Замыкание - объект лексического окружения
const LE = {
environmentsRecords: {},
outer: LE || null,
}
Лексическое окружение - блок кода или функция.
Замыкание возникает тогда, когда функция возвращает другую функцию. Функцию, которую вернули можно сохранить в какую-то переменную. Таким образом внешнее окружение, в которой была создана функция, мы его запоминаем, оно может быть использовано, когда внешняя функция будет удалена (ее лексическое окружение будет удалено), но этого не происходит, так как работает замыкание.
в свойство environmentRecords будут записываться все созданные переменные, то есть работа с переменными это работа с ключами environmentRecords.
outer - ссылка на внешнее лексическое окружение, когда null - если глобальная зона видимости
LE формируется для скрипта (globalLE), для функции (functionalLE) и для блоков кода. Объект не формирует LE!
Замыкание в JavaScript — это механизм работы с областями видимости, который позволяет сохранять доступ к переменным даже после завершения работы функции, в которой эти переменные были объявлены.
Есть блоки кода, которые обозначаются фигурными скобками - внутри каждого кода создается свой объект, к которому мы не имеем доступа (читать, записывать и тд). В каждом таком блоке кода создается объект лексического окружения, который состоит из компонент:
const LE = {
environmentsRecords: {} - сами переменные этой функции, в которой они объявлены,
outer: LE || null - ссылка на внешнее лексическое окружение , т.е. если это функция, то она будет объявлена в каком-то другом лексическом окружении внутри другой функции, внутри какого-то блока кода (if … else, for, while, switch), внутри глобального лексического окружения. Аргументы самой функции не попадают в лексическое окружение.
}
Пример.
//globalLE {} –> null
startEngine()
let car = ‘bmw’ //globalLE {car: ‘bmw’} –> null
const startEngine = function () {
//startEngineLE {} –> globalLE
const car = ‘kia’ // startEngineLE {car: ‘kia’} –> globalLE
console.log(Start ${car}
)
}
startEngine() //globalLE {startEngine: function} –> null
car = ‘audi’ //globalLE {startEngine: function, car: ‘audi’} –> null
startEngine()
Для организации замыкания необходимы три компонента:
- Внешняя функция, которая определяет некоторую область видимости и в которой определены некоторые переменные (лексическое окружение).
- Переменные (лексическое окружение), которые определены во внешней функции.
- Вложенная функция, которая использует эти переменные.
Для собеса “Почему, где car происходит ошибка?”:
let car = ‘bmw’
function starEngine () {
const model = ‘520’
const func = () => {
console.log(‘Start’ ${car} model: ${model}
const car = ‘kia’
)}}
Видит, что есть такая переменная в этой функции, но ее еще нельзя использовать.
Пример по замыканию:
let car = ‘bmw’
function starEngine () {
const model = ‘520’
const func = () => {
model = model + ‘’ + model
console.log(‘Start’ ${car} model: ${model}
)}
return func
}
const calculateModel = starEngine ()
calculateModel () // Start bmw model : 520520
calculateModel () Start bmw model : 520520520520
calculateModel ()Start bmw model : 520520520520520520
Значение ‘model’ каждый раз будет браться из внешней модели, мутирует значение. Не создаем новый starEngine, пользуемся старым. starEngine не удаляется из памяти, так как не удаляется объект из лексического окружения.
Есть ссылка на внутреннюю функцию на внешнюю функцию, за счет этого в нашей внешней функции не может удалена из памяти, потому что на ее лексическое окружение кто-то ссылается.
!Инициализация не объявленной переменной приводит к созданию переменной на глобальном уровне
Всплытие:
var и functionDeclaration всплывают до ближайшей функции, на глобальном уровне - недоступна.
var - может всплыть до глобальной функции
let, const не всплывает, все происходит под капотом.
Возможность функции использовать переменные из внешнего лексического окружения сама по себе — это лексическая область видимости (lexical scoping), а замыкание возникает тогда, когда эта функция сохраняется и продолжает “удерживать” доступ к этим переменным после завершения выполнения внешней функции.
То есть замыкание - это способность функции запомнить в каком лексическом окружении ее создали и иметь доступ к этому окружению даже после завершения выполнения внешней функции.
Если мы хотим, чтобы функция доставалась из кэша:
const sqr = (num: number) => {
return num * num
}
memoizedSqr = memoize(sqr);
function memoize (fn){
const cashe = {}
return function (arg){
if (cashe[arg]) {
return cashe[arg]
}
const result = fn (arg)
cashe[arg] = result;
return result;
}
}
console.log(memoizedSqr(5)) //calculation
console.log(memoizeSqr(5)) // from cashe
console.log(memoizedSqr(6)) //calculation
console.log(memoizeSqr(5)) // from cashe