针对前端必会的闭包,梳理一番,妈妈再也不用担心我的闭包了~~~~

235 阅读2分钟

闭包

1.1 什么是闭包

  • 闭包(closure): 指有权访问另一个函数作用域中变量的函数。
  • 通俗讲:一个作用域可以访问另外一个函数内部的局部变量。

1.2 观察下面代码的结果

for(var i = 0; i < 10; i++) {  
    setTimeout(function() {  
        console.log(i);
    }, 1000);  
}
//输出结果都为10,因为for()循环过程中每次传值,匿名函数并没有执行,相当于执行10次function(){console.log(i);},循环结束i变为10,所以输出全部为10;
for(var i = 0; i < 10; i++) {  
    (function(i) {  
        setTimeout(function() {  
            console.log(i);
        }, 1000);  
    })(i);  
}
//外部匿名函数立即执行,把 i 作为参数,赋值给内部的 i ,因为是立即执行,所以每次循环输出不同值。

1.3 变量的作用域与同步异步复习

变量根据作用域的不同分为两种:全局变量和局部变量

  • 函数内部可以使用全局变量。
  • 函数外部不可以使用局部变量。
  • 当函数执行完毕,本作用域内的局部变量会销毁。

同步异步

  • 同步:由于js单线程,同步任务都在主线程上排队执行,前面任务没执行完成,后面的任务会一直等待;

  • 异步:不进入主线程,进入任务队列,等待主线程任务执行完成后开始执行。比如我们学的异步操作setTimeout和setInterval,等待主线程任务执行完,在开始执行里面的函数

1.3闭包的作用

  • 特性:可实现函数外访问函数内变量,外层变量可以不被垃圾回收机制回收,即延伸变量的作用范围

  • 缺点: 引用外层变量不被回收,会相比其他函数占用更高内存,使用不当容易造成内存泄漏。

1.4 经典案例

利用闭包的方式得到当前li 的索引号

for (var i = 0; i < lis.length; i++) {
// 利用for循环创建了立即执行函数
// 立即执行函数也成为小闭包因为立即执行函数里面的任何一个函数都可以使用它的i这变量
(function(i) {
    lis[i].onclick = function() {
      console.log(i);
    }
 })(i);
}

方法二: 使用自定义属性,给每个对象添加一个索引属性

for (var i = 0; i < lis.length; i++) {
function(i) {
    lis[i].index = i;
    lis[i].onclick = function() {
      console.log(this.index);
    }
 }
}

方法三: 利用ES6 的 Let 声明变量就可以更好的解决上述问题

for (let i = 0; i < lis.length; i++) {
function(i) {
    lis[i].onclick = function() {
      console.log(i)
    }
 }
}