在上次的分享中javascript--函数参数与闭包--详解,对闭包的解释不够深刻。本人通过一段时间的学习,对闭包的概念又有了新的理解。因而便把学习的过程整理成文章,一是为了加深本身闭包的理解,二是给读者提供学习的途径,避免走弯路。javascript
如下的分享会分为以下内容:html
1.let命令java
2.闭包特色的解读闭包
3.循环中的闭包函数
1.let命令post
在讲闭包前,有必要谈谈ES6中的新概念,let命令。由于在赘述循环中的闭包时会使用到let命令。性能
基本用法学习
ES6新增了let
命令,用来声明变量。它的用法相似于var
,可是所声明的变量,只在let
命令所在的代码块内有效。url
1 if (true) { 2 var a = 1; 3 let b = 2; 4 } 5 console.log(a); // 1 6 console.log(b); // ReferenceError: b is not defined
在javascript--函数参数与闭包--详解中,谈到在局部变量只能在函数内部声明,在其余代码(如 if 条件语句,for循环语句)用 var 声明的变量都为全局变量。spa
在上面代码中,分别用 let
和 var
声明了两个变量。而后在代码块以外调用这两个变量,结果 let
声明的变量报错,var
声明的变量返回了正确的值。这代表,if 条件语句中使用var声明的变量为全局变量,能够在全局做用域下访问。而 let
声明的变量只在它所在的代码块有效,在全局做用域下没法访问。
再来看看这两个例子。
1 for (let i = 0; i < 10; i++) {} 2 console.log(i); //ReferenceError: i is not defined
1 for (var i = 0; i < 10; i++) {} 2 console.log(i); // 10
2.闭包特色的解读
咱们知道,闭包有三个特色
a:在一个函数内部定义另一个函数,并返回内部函数或当即执行内部函数。
b:内部函数能够访问外部函数定义的局部变量 (变量采用var声明)
c:让局部变量始终保存在内存中。也就是说,闭包能够使得它诞生的环境一直存在。
咱们来看一个例子,尝试串起这三个特色。
1 function keith() { 2 var a = 1; 3 return function() { 4 return a++; 5 } 6 } 7 var result = keith(); 8 console.log(result()); //1 9 console.log(result()); //2 10 console.log(result()); //3
首先,在函数keith内部返回了一个匿名函数,若是函数keith没有返回值,则默认返回值为undefined。
而后,由于在函数keith中返回了一个匿名函数,又把调用函数keith的结果赋值给了全局变量result,因此全局变量result是一个闭包。当连续调用result时,依次返回1,2,3。返回值说明了内部函数能够访问外部函数定义的局部变量。也就是说,闭包记住了外部函数定义的局部变量的调用结果。
最后,由于咱们把一个闭包赋值给了一个全局变量result,在调用时依次输出1,2,3。说明了在函数keith外部访问的这个局部变量a一直存在全局做用域中。也就是说,局部变量 a 一直存在于内存当中,因此不会被垃圾回收机制回收。
因此使用闭包的时候的注意点:
因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题,在IE中可能致使内存泄露。解决方法是,在退出函数以前,将不使用的局部变量所有删除。
3.循环中的闭包
一个常见的错误出如今循环中使用闭包,假设咱们须要在每次循环中调用循环序号。
1 for (var i = 0; i < 10; i++) { 2 setTimeout(function() { 3 console.log(i); //10 4 }, 1000) 5 }
上面代码中,不会符合咱们的预期,输出数字0-9。而是会输出数字10十次。
出现错误的缘由在于咱们在setTimeout函数里面定义了一个匿名函数,匿名函数的做用是在控制台输出变量 i,而变量 i 是一个全局变量,在全局范围内都有效。因此每一次循环,新的 i
值都会覆盖旧值,致使最后输出的是最后一轮的i
的值。
因此,针对循环中的闭包,有如下两种解决方法。
一是使用当即执行函数(IIFE),并把 i
做为它的参数,此时函数内 e
变量就拥有了 i
的一个拷贝。当传递给 setTimeout
的匿名函数执行时,它就拥有了对 e
的引用,而这个值是不会被循环改变的。
1 for (var i = 0; i < 10; i++) { 2 (function(e){ 3 setTimeout(function() { 4 console.log(e); //1,2,3,....,10 5 }, 1000) 6 })(i) 7 }
二是让变量 i 只在代码块中有效。也就是说让其成为局部变量。变量 i
是 let
声明的,当前的 i
只在本轮循环有效,因此每一次循环的 i
其实都是一个新的变量,因此最后输出的是1,2,3,4....,10。
1 for (let i = 0; i < 10; i++) { 2 setTimeout(function() { 3 console.log(i); //1,2,3...,10 4 }, 1000) 5 }
完。
感谢你们的阅读。