介绍你下你理解的闭包?不管怎样!我最近听到很多次!感觉是不好好总结一下没法面对那些犀利的追问!
如果觉得闭包理解的很透彻,就直接跳到最后看题目!

1.闭包概念

小红书的解释闭包是有权访问另一个函数作用域中的变量的函数。明白了吗?就是一个函数,一个可以访问其他函数中变量的函数。所以常见的创建闭包的方式就是在一个函数内部创建另一个函数。

function bag(num){    return function(){        return num    }}var bagc = bag(12)console.log(bagc()) //12

可以看到在bag内部的匿名函数可以访问外部bag函数的变量num。

2.闭包的用处

闭包可以用在许多地方。它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中

function f1(){     var n=999;     nAdd=function(){n+=1}    function f2(){      alert(n);    }    return f2;}var result=f1();result(); // 999 nAdd(); //变量n被保存了result(); // 1000

上面是阮一峰在文档中的一个例子,读取函数内部变量我觉得用处一般吧,让变量保持在内存中的用处倒是不少,像经常使用的that=this等。下面看一个常见的问题:

 for(var i = 0;i <10;i++){     setTimeout(()=>{        console.log(i)     },1000)  }  //上面的代码我们希望按照索引值打印,结果却打印了10个10,为什么就不解释了,i是全局变量。  //换成下面的写法,就能解决问题,正是因为闭包 让变量的值始终保持在内存中,每个i都存在了num这个局部变量中              for(var i = 0;i <10;i++){      (function(num){         setTimeout(()=>{            console.log(num)         },1000)       })(i)   }

3.使用闭包需要注意的点

闭包虽然在解决一些问题上有好处,但是由此引发的一些问题要注意,而且由于闭包会携带外部函数作用域,所以内存占用比较大,所以尽量少用、慎用闭包。

1.变量问题

正是因为闭包可以使用外部变量,所以下面的代码中,返回的匿名函数中对变量i的使用将会是最终的值,数组中存放的函数的返回值将都会是10。

function test() {   var result = [];   for(var i = 0; i<10; i++){      result.[i] = function () {         return i;      }   }   return result}

需要将上述代码改写成如下:

function test() {   var result = [];   for(var i = 0; i<10; i++){      result.[i] = function (num) {         return function() {           console.info(num);           }      }(i)   }   return result}

此时访问的num,是上层函数执行环境的num,数组有10个函数对象,每个对象的执行环境下的number都不一样。

2.this问题

匿名函数的执行具有全局性,所以闭包函数的this一般指向window;

var object = {     name: "object",     getName:function() {        return function() {             console.info(this.name)        }    }}object.getName()()    // underfined// 因为里面的闭包函数是在window作用域下执行的,也就是说,this指向windows

可以改写成如下:

var object = {     name: "object",     getName:function() {        var that = this;        return function() {             console.info(that.name)        }    }}object.getName()()    // object

3.内存泄漏问题

如果闭包在作用域链中保存着html元素,则该元素内存将无法自动销毁。

function  showId() {    var el = document.getElementById("app")    el.onclick = function(){      aler(el.id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放    }}// 改成下面function  showId() {    var el = document.getElementById("app")    var id  = el.id    el.onclick = function(){      aler(id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放    }    el = null    // 主动释放el}

4.闭包练习题

好了,看到这里是不是感觉对闭包理解的很到位了?别着急,看看这两个小问题测试一下!

1.与函数调用结合

var Test = {    close:function(val){        return function (z){            return ++ val +z        }    }}var getClose = function(val){    return Test[val]}                         var fn = getClose('close')var cover = fn(100)console.log(cover(200)) console.log(cover(300))console.log(fn(100)(200))console.log(fn(100)(200))console.log(getClose('close')(100)(300))//输出结果见结尾处

2.与dom结合

var container1 = document.getElementById('container1')var container2 = document.getElementById('container2')var container3 = document.getElementById('container3')var container4 = document.getElementById('container4')var container5 = document.getElementById('container5')var innerHTML = 'window的html'var events = {    innerHTML:'我是events',    getHtml:function (){        console.log(this.innerHTML)    },    setFun:function(){        return this.getHtml    },    proxy:function(){        var self = this;        return function(){            self.getHtml()        }    }}container1.onclick = events.getHtml; container2.onclick = events.setFun();container3.onclick = events.proxy();container4.onclick = function(){    window.setTimeout(events.setFun(),0)}container5.onclick = function(){    window.setTimeout(events.proxy(),0)}

还ok?有没有被绕晕!晕了就打开电脑敲吧

看一下输出结果吧第一题:401 402 301 301 401第二题:container container2 我是events window的html 我是events