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