什么是闭包?MDN给出的定义是,能够从内部函数访问外部函数作用域的状态闭包并不是什么稀罕事。闭包在JavaScript中无处不在,闭包不是一种语法,而是基于词法----根据变量在源代码中声明的位置来确定变量在何处可用----写法的自然结果范围内的代码,所以在实际写包的时候可能不会刻意使用,但是大概率会产生闭包,比如:functioninit(){letname="sifou";//name是由initfunctiondisplayName()创建的局部变量{//displayName()是一个内部函数,一个Closurealert(name);//使用父函数中声明的变量}displayName();}init();//按照前面的定义,sifou看起来不像,因为displayName函数是嵌套在init里面的,根据作用域链的查找规则,能够使用上层作用域的变量是正常的,而这个搜索规则是关闭的最重要原因。修改以上代码:functioninit(){letname="sifou";//name是由initfunctiondisplayName()创建的局部变量{//displayName()是一个内部函数,一个闭包alert(name);//使用父函数中声明的变量}returndisplayName}constoutFn=init();outFn()//由于sifou的函数可以传值,所以outFn和displayName实际上是通过不同的标识符调用了内部函数displayName,并且它们是自己定义的词法函数,在域外执行。按理来说,当init执行结束,垃圾回收机制应该被回收,它的整个内部作用域应该被销毁。闭包阻止了这种情况的发生,因为该范围仍在使用,并且由displayName使用。displayName仍然持有该范围的引用。整个引用是一个闭包。当然,这意味着无论函数类型的值如何传递,在其他地方调用该函数时,都可以看到闭包Package.本质一般来说,如果一个函数作为值类型传递,就会有一个闭包。比如在定时器、事件监听器、Ajax请求等任务中,只要用到回调函数,其实就是一个闭包,这正是我开头所说的。国内到处都是闭包一道经典的闭包面试题://Retrofittoprint1,2,3,4,5for(vari=1;i<=5;i++){setTimeout(functiontimer(){console.log(i)},i*1000)}//转换后for(vari=1;i<=5;i++){(function(j){setTimeout(functiontimer(){console.log(j)},j*1000)})(i)}转换后可以打印1,2,3,4,5的原因和使用let----block-levelscope的原因类似,在迭代内部使用IIFE会A每次迭代都会产生新的作用域,这样延迟函数的回调可以在每次迭代内部关闭新的作用域,并且由于闭包的存在(定时器使用形参j),在IIFE之后executed不会被回收,所以每次迭代都有一个正确的变量值可以访问
