Статья полностью понимает закрытие Javascript (включая закрытие высокочастотных вопросов интервью)

опрос
Статья полностью понимает закрытие Javascript (включая закрытие высокочастотных вопросов интервью)

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

Закрытие простое для понимания内嵌函数, то есть в函数中嵌套函数.

Поскольку в 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: ƒ}