Замыкание — это функция, которая имеет доступ к переменным в области видимости другой функции.
Закрытие простое для понимания内嵌函数, то есть в函数中嵌套函数.
Поскольку в JS область переменных принадлежит области видимости функции, область действия будет очищена и память будет восстановлена после выполнения функции, но поскольку замыкание является подфункцией, встроенной внутри функции, она может получить доступ к Superior Причина области видимости в том, что даже если функция верхнего уровня будет выполнена, область видимости не будет уничтожена, в это время подфункция, то есть замыкание, имеет право доступа к переменным в верхнем уровне. -level scope, даже если выполняется функция верхнего уровня.Значения в задней области видимости также не уничтожаются.
закрыто形成, Переменная作用域И переменные生存周期тесно связаны.
1. Объем переменных
Область действия переменной относится к эффективной области действия переменной.
В цепочке областей видимости, созданной средой выполнения кода, внешний уровень просматривается слой за слоем, пока не будет найден глобальный объект.
2. Жизненный цикл переменных
- Для глобальных переменных жизненный цикл является постоянным, если только они не будут активно уничтожены.
- Как правило, для области действия функции или локальной области (пусть const) она будет уничтожена в конце вызова функции.
- Когда функция вызывает внешнюю переменную, она генерируется
闭包, в это время стратегия восстановления переменных может относиться к引用计数Ждать垃圾回收策略.
3. Утечка памяти
Поскольку js-объекты IE и объекты DOM используют разные методы сборки мусора, замыкания вызовут утечку памяти в IE, то есть элементы DOM в памяти не могут быть уничтожены.
Поэтому, когда нам не нужно использовать dom, мы должны разыменовать dom, чтобы избежать утечек памяти.
function closure(){
// div用完之后一直存在内存中,无法被回收
var div = document.getElementById('div');
div.onclick = function () {
console.log(div.innerHTML);// 这里用oDiv导致内存泄露
};
}
// 解除引用避免内存泄露
function closure(){
var div = document.getElementById('div');
var test = div.innerHTML;
div.onclick = function () {
console.log(test);
};
div = null;
}
4. Резюме закрытия
- форма:функция внутри функции
- эффект:Вызов внешних переменных внутри функций, приватные свойства конструкторов, продление жизненного цикла переменных
- преимущество:Надежда на то, что переменная существует в памяти долгое время, модульный код позволяет избежать загрязнения глобальных переменных, частных свойств
- недостаток:Переменная, на которую ссылается замыкание, не может быть восстановлена, что может привести к утечке памяти.
5. Применение замыканий
Замыкания могут значительно улучшить свободу организации кода и имеют очень широкий спектр применения в повседневном использовании.
Простые:
- Успешный обратный вызов для запроса ajax
- Метод обратного вызова привязки события
- Задержка обратного вызова setTimeout
- Внутри функция возвращает другую анонимную функцию
Мы подробно опишем следующие сценарии применения:
- Частная собственность конструктора
- Вычислительный кеш
- Функция троттлинга, стабилизация изображения
5.1 частная собственность конструктора
- Поскольку в javascript нет реализации класса, некоторые вещи, которые не хотят модифицироваться извне
私有属性Этого можно добиться с помощью замыканий.
function Person(param) {
var name = param.name; // 私有属性
this.age = 18; // 共有属性
this.sayName = function () {
console.log(name);
}
}
const tom = new Person({name: 'tom'});
tom.age += 1; // 共有属性,外部可以更改
tom.sayName(); // tom
tom.name = 'jerry';// 共有属性,外部不可更改
tom.sayName(); // tom
5.2 Вычислительный кеш
// 平方计算
var square = (function () {
var cache = {};
return function(n) {
if (!cache[n]) {
cache[n] = n * n;
}
return cache[n];
}
})();
5.3 Функция дросселирования, защита от сотрясений
// 节流
function throttle(fn, delay) {
var timer = null, firstTime = true;
return function () {
if (timer) { return false;}
var that = this;
var args = arguments;
fn.apply(that, args);
timer = setTimeout(function () {
clearTimeout(timer);
timer = null;
}, delay || 500);
};
}
// 防抖
function debounce(fn, delay) {
var timer = null;
return function () {
var that = this;
var args = arguments;
clearTimeout(timer);// 清除重新计时
timer = setTimeout(function () {
fn.apply(that, args);
}, delay || 500);
};
}
6. Заключительные часто задаваемые вопросы на собеседовании (понимание кода)
// 1
for ( var i = 0 ; i < 5; i++ ) {
setTimeout(function(){
console.log(i);
}, 0);
}
// 5 5 5 5 5
// 2
for ( var i = 0 ; i < 5; i++ ) {
(function(j){
setTimeout(function(){
console.log(j);
}, 0);
})(i);
// 这样更简洁
// setTimeout(function(j) {
// console.log(j);
// }, 0, i);
}
// 0 1 2 3 4
setTimeout(function(j) {
console.log(j);
}, 0, i);
// 3
for ( let i = 0 ; i < 5; i++ ) {
setTimeout(function(){
console.log(i);
},0);
}
// 0 1 2 3 4
// 4
var scope = 'global scope';
function checkscope(){
var scope = 'local scope';
console.log(scope);
}
// local scope
// 5
var scope = 'global scope';
function checkscope(){
var scope = 'local scope';
return function f(){
console.log(scope);
};
}
var fn = checkscope();
console.log(fn()); // local scope
// 6
var scope = 'global scope';
function checkscope(){
var scope = 'local scope';
return function f(){
console.log(scope);
};
}
checkscope()(); // local scope
var obj = {
name: 'tom',
sayName() {
console.log(this.name);
}
}
obj.sayName(); // tom
var obj = {
name: 'tom',
sayName() {
var name = 'alan';
console.log(this.name);
}
}
obj.sayName();// 'tom'
var name = 'jerry';
var obj = {
name : 'tom',
sayName(){
return function(){
console.log(this.name);
};
}
};
obj.sayName()(); // jerry
// var name = 'jerry';
var obj = {
name: 'tom',
sayName() {
var name = 'alan';
console.log(this.name);
}
};
var sayName = obj.sayName;
sayName(); // '' // jerry
function fun(a,b) {
console.log(b)
return {
fun: function(c) {
return fun(c,a);
}
};
}
var d = fun(0); // undefined
d.fun(1); // 2 0
d.fun(2); // 2 0
d.fun(3); // 2 0
var d1 = fun(0).fun(1).fun(2).fun(3);
// 2 undefined 2 0
// 2 1
// 2 2
var d2 = fun(0).fun(1); d2.fun(2);
// 2 undefined
// 2 0
// 2 1
// 2 1
d2.fun(3); // {fun: ƒ}