不断更新:整理常见的闭包问题

不断积累和整理在JavaScript中常见的闭包问题,不断加深理解和学习运用:


 参考MDN网址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

闭包的官方定义: 闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量(摘自MDN)

闭包的简单理解:希望在另一个作用域(比如在global中)访问局部作用域中的某个变量或函数

(在谷歌浏览器中调试,发生闭包会有closure字样提示)

问题一:闭包的“雏形”:在全局作用域中访问某局部作用域中的变量或函数:

function fn() {

  var name =  'zs';

  return function () {

    return name;  

  }

}

var f = fn();

var n = f(); 

//或者这样写: var n= fn()();

console.log(n) //zs

问题二:用闭包解决在for循环中绑定事件的问题

假设不使用闭包解决这个问题,点击绑定的li的值输出的都是最后的一个值,因为触发点击事件的时候for循环已经结束了,且在for循环的作用域中 i 的值不断被覆盖

var list = document.getElementByTagName('li');

for (var i = 0 ;i < list.length ;i++){
    var li = list[i];
    ( function (index){
         li.onclick = function(){
             alert( index );
        }    
    })(i)
}    

自执行函数从全局作用域中访问for循环里面的 i, 给每个 i 都新开创了一个作用域,让它保存i的值 

但过多的开创独立作用域,会造成额外的开销消耗性能,所以闭包有利有弊,像上面这种问题可以使用let来解决

延伸:其他解决改问题的方法(使用let定义i)

var list = document.getElementByTagName('li');

for (let i = 0 ;i < list.length ;i++){
         li.onclick = function(){
             alert( i );
        }    
}    

问题三:用闭包解决在for循环中 setTimeout() 的问题

console.log(111)
for ( var i = 0 ; i<3 ; i++){
     setTimeout(function () {
          console.log(i)
    }, 0 )  
}
console.log(222)

最后的执行结果:
111
222
3
3
3

当js执行到setTimeout时会将其自动放入异步队列中去等待,直到主代码执行完后再去执行异步队列中的代码,于是3个3会在最后出现

使用闭包的方法避免这种情况:

console.log(111)
for ( var i = 0 ; i<3 ; i++){
    (function (index){
        setTimeout(function () {
          console.log(i)
        }, 0 )  
    })(i)
}
console.log(222)
输出结果:
111
222
0
1
2

问题四:从闭包的角度给button等元素绑定事件demo

<a href="#" id="size-12">12</a>
<a href="#" id="size-14">14</a>
<a href="#" id="size-16">16</a>
function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;

size12size14 和 size16 三个函数将分别把 body 文本调整为 12,14,16 像素。我们可以将它们分别添加到按钮的点击事件上。

总结:

 上面是闭包的几个典型例子,除此之外闭包常见的问题还有用闭包模拟私有方法等等,同时要注意开创闭包后要给它赋值为null来清除,避免其常驻内存,造成内存泄漏等问题影响性能,当然还有其他方式。

闭包考量性能,既实用,同时也有弊端。

运用好闭包是掌握JS的重点之一。革命尚未成功,同志仍需努力!

原文地址:https://www.cnblogs.com/lwj-blog/p/11357441.html