深入理解javascript闭包(二)
在上次的分享中javascript--函数参数与闭包--详解,对闭包的解释不够深入。本人经过一段时间的学习,对闭包的概念又有了新的理解。于是便把学习的过程整理成文章,一是为了加深自己闭包的理解,二是给读者提供学习的途径,避免走弯路。
以下的分享会分为如下内容:
1.let命令
2.闭包特点的解读
3.循环中的闭包
1.let命令
在讲闭包前,有必要谈谈ES6中的新概念,let命令。因为在赘述循环中的闭包时会使用到let命令。
基本用法
ES6新增了let
命令,用来声明变量。它的用法类似于var
,但是所声明的变量,只在let
命令所在的代码块内有效。
if (true) { var a = 1; let b = 2; } console.log(a); console.log(b); // ReferenceError: b is not defined
在javascript--函数参数与闭包--详解中,谈到在局部变量只能在函数内部声明,在其他代码(如 if 条件语句,for循环语句)用 var 声明的变量都为全局变量。
在上面代码中,分别用 let
和 var
声明了两个变量。然后在代码块之外调用这两个变量,结果 let
声明的变量报错,var
声明的变量返回了正确的值。这表明,if 条件语句中使用var声明的变量为全局变量,可以在全局作用域下访问。而 let
声明的变量只在它所在的代码块有效,在全局作用域下无法访问。
再来看看这两个例子。
for (let i = 0; i < 10; i++) {} console.log(i); //ReferenceError: i is not defined
for (var i = 0; i < 10; i++) {} console.log(i);
2.闭包特点的解读
我们知道,闭包有三个特点
a:在一个函数内部定义另外一个函数,并返回内部函数或立即执行内部函数。
b:内部函数可以访问外部函数定义的局部变量 (变量采用var声明)
c:让局部变量始终保存在内存中。也就是说,闭包可以使得它诞生的环境一直存在。
我们来看一个例子,尝试串起这三个特点。
function keith() { var a = 1; return function() { return a++; } } var result = keith(); console.log(result()); console.log(result()); console.log(result());
首先,在函数keith内部返回了一个匿名函数,如果函数keith没有返回值,则默认返回值为undefined。
然后,因为在函数keith中返回了一个匿名函数,又把调用函数keith的结果赋值给了全局变量result,所以全局变量result是一个闭包。当连续调用result时,依次返回1,2,3。返回值说明了内部函数可以访问外部函数定义的局部变量。也就是说,闭包记住了外部函数定义的局部变量的调用结果。
最后,因为我们把一个闭包赋值给了一个全局变量result,在调用时依次输出1,2,3。说明了在函数keith外部访问的这个局部变量a一直存在全局作用域中。也就是说,局部变量 a 一直存在于内存当中,所以不会被垃圾回收机制回收。
所以使用闭包的时候的注意点:
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
3.循环中的闭包
一个常见的错误出现在循环中使用闭包,假设我们需要在每次循环中调用循环序号。
for (var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 1000) }
上面代码中,不会符合我们的预期,输出数字0-9。而是会输出数字10十次。
出现错误的原因在于我们在setTimeout函数里面定义了一个匿名函数,匿名函数的作用是在控制台输出变量 i,而变量 i 是一个全局变量,在全局范围内都有效。所以每一次循环,新的 i
值都会覆盖旧值,导致最后输出的是最后一轮的i
的值。
所以,针对循环中的闭包,有以下两种解决方法。
一是使用立即执行函数(IIFE),并把 i
作为它的参数,此时函数内 e
变量就拥有了 i
的一个拷贝。当传递给 setTimeout
的匿名函数执行时,它就拥有了对 e
的引用,而这个值是不会被循环改变的。
for (var i = 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 (let i = 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闭包,直到有人这样向我解释它...
摘要: 理解JS闭包. 原文:我从来不理解JavaScript闭包,直到有人这样向我解释它... 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 正如标题所述,JavaScript闭包 ...
- 【转】深入理解JavaScript闭包闭包(closure) (closure)
一.什么是闭包?"官方"的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述 ...
- 全面理解Javascript闭包和闭包的几种写法及用途
好久没有写博客了,过了一个十一长假都变懒了,今天总算是恢复状态了.好了,进入正题,今天来说一说javascript里面的闭包吧!本篇博客主要讲一些实用的东西,主要将闭包的写法.用法和用途. 一.什么 ...
- 深入理解JavaScript闭包(closure)
最近在网上查阅了不少javascript闭包(closure)相关的资料,写的大多是非常的学术和专业.对于初学者来说别说理解闭包了,就连文字叙述都很难看懂.撰写此文的目的就是用最通俗的文字揭开Java ...
- 深入理解javascript闭包(一)
闭包(closure)是Javascript语言的一个难点.也是它的特色,非常多高级应用都要依靠闭包实现. 一.什么是闭包? 官方"的解释是:闭包是一个拥有很多变量和绑定了这些变量的环境的表 ...
- 深入理解javascript闭包(一)
原文转自脚本之家(http://www.jb51.net/article/24101.htm) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. ...
- 深入理解Javascript闭包概念
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部能够直接读取全局变量 ...
- 轻松理解JavaScript闭包
摘要 闭包机制是JavaScript的重点和难点,本文希望能帮助大家轻松的学习闭包 一.什么是闭包? 闭包就是可以访问另一个函数作用域中变量的函数. 下面列举出常见的闭包实现方式,以例子讲解闭包概念 ...
- 【译】理解JavaScript闭包——新手指南
闭包是JavaScript中一个基本的概念,每个JavaScript开发者都应该知道和理解的.然而,很多新手JavaScript开发者对这个概念还是很困惑的. 正确理解闭包可以帮助你写出更好.更高效. ...
- 转 全面理解Javascript闭包和闭包的几种写法及用途
转自:http://www.cnblogs.com/yunfeifei/p/4019504.html 好久没有写博客了,过了一个十一长假都变懒了,今天总算是恢复状态了.好了,进入正题,今天来说一说ja ...
随机推荐
- appium+robotframework环境搭建
appium+robotframework环境搭建步骤(Windows系统的appium自动化测试,只适用于测试安卓机:ios机需要在mac搭建appium环境后测试) 搭建步骤,共分为3部分: 一. ...
- 学习笔记:Maven构造版本号的方法解决浏览器缓存问题
需要解决的问题 在做WEB系统开发时,为了提高性能会利用浏览器的缓存功能,其实即使不显式的申明缓存,现代的浏览器都会对静态文件(js.css.图片之类)缓存.但也正因为这个问题导致一个问题,就是资源的 ...
- .NET面试题系列[7] - 委托与事件
委托和事件 委托在C#中具有无比重要的地位. C#中的委托可以说俯拾即是,从LINQ中的lambda表达式到(包括但不限于)winform,wpf中的各种事件都有着委托的身影.C#中如果没有了事件,那 ...
- 更有效率的使用Visual Studio(二)
没想到上一篇文章有这么多人喜欢,多谢大家支持.继续- 很多比较通用的快捷键的默认设置其实是有一些缩写在里面的,这个估计也是MS帮助我们记忆.比如说注释代码的快捷键是Ctrl + E + C,我们如果知 ...
- 详解this
this 虐我千百遍,看完此文效立见!不得不说,这篇文章的总结很地道很全面,适合收藏之用. 原文:all this 习惯了高级语言的你或许觉得JavaScript中的this跟Java这些面向对象语言 ...
- xamarin android ListView手动分组
xamarin的listview控件其实自带有分组方法,关于xamarin listview的自带分组方法请自行参考官方文档,我这里只写自己写的分组方法.xamarin自带的分组好是好,功能多,但是加 ...
- 配置hibernate,Struts。文件
hibernate文件配置 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernat ...
- iOS---正确使用NSNotification对象
我们在开发程序的时候,程序内不同对象间的通信是不可避免的,iOS中主要有以下这些通信方式: iOS中的通信方式 图中按照耦合度的强弱和通信的形式(一对一还是一对多)进行了划分,这篇文章我们主要说一下N ...
- vue vue-cli安装
npm 更新 cnpm install -g npm Vue 的基本用法 Vue 相比于 React 和 Angular 容易上手多了,因此我对 Vue 的学习主要以文档为主,视频为辅(只有像我这种菜 ...
- php后台增删改跳转
php登录页面: <h1>登录界面</h1> <form action="dengluchuli.php" method="post&quo ...