javascript中重要概念-闭包-深入理解
在上次的分享中javascript--函数参数与闭包--详解,对闭包的解释不够深入。本人经过一段时间的学习,对闭包的概念又有了新的理解。于是便把学习的过程整理成文章,一是为了加深自己闭包的理解,二是给读者提供学习的途径,避免走弯路。
在javascript--函数参数与闭包--详解这篇文章中,我详细介绍了闭包的概念。以下的分享对闭包的基本概念只会稍稍带过。如果对闭包的概念不熟悉的同学,请移步至javascript--函数参数与闭包--详解。
以下的分享会分为如下内容:
1.let命令
2.闭包特点的解读
3.循环中的闭包
1.let命令
在讲闭包前,有必要谈谈ES6中的新概念,let命令。因为在赘述循环中的闭包时会使用到let命令。
基本用法
ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

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 声明的变量都为全局变量。
在上面代码中,分别用 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 }
javascript中重要概念-闭包-深入理解的更多相关文章
- JavaScript中call、apply个人理解
JavaScript中call.apply个人理解 一句话即通俗的说:call.apply 是为了改变this的状态而存在的 }; } function personInfo(name,age){ t ...
- JavaScript作用域链与闭包的理解
作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域 链的工作原理. 1. 全局作用域(Global Scope) (1)最外层函数和 ...
- javascript 中的new操作符的理解
new 操作符 在有上面的基础概念的介绍之后,在加上new操作符,我们就能完成传统面向对象的class + new的方式创建对象,在Javascript中,我们将这类方式成为Pseudoclassic ...
- 对JavaScript中变量类型的重新理解
<JavaScript启示录>这本书中提出:JavaScript中,对象为“王”(JavaScript里的几乎所有东西都是对象或者用起来像对象). 飞燕草对JavaScript最深刻的理解 ...
- javascript匿名函数及闭包深入理解及应用
1.匿名函数 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没有函数名的函数. 1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式 第一种: ...
- javascript中对象字面量的理解
javascript中对象字面量与数组字面量 第一部分 我们知道JavaScript中的数据类型有基本数据类型和引用类型,其中Object类型就是非常常用的类型.那么如果创建一个Object类型的实例 ...
- JavaScript中一些怪异用法的理解
引言 JavaScript这门语言有些场合的用法还是比较怪异的.这篇文章会尽量将这门语言特有的一些比较特殊的用法收集在一起.就当是平时开发时需要注意的地方吧. 特殊用法收集 1.!!用法 在JavaS ...
- JavaScript中的this对象指向理解
在JavaScript中,this不是固定不变的,它的指向取决于上下文环境,一般的,认为this指向使用它时所在的对象.主要有以下几类指向: 在方法中,this 表示该方法所属的对象. 如果单独使用, ...
- JavaScript 中一些概念理解 :clientX、clientY、offsetX、offsetY、screenX、screenY
clientX 设置或获取鼠标指针位置相对于窗口客户区域的 x 坐标,其中客户区域不包括窗口自身的控件和滚动条. clientY 设置或获取鼠标指针位置相对于窗口客户区域的 y 坐标,其中客户区域不包 ...
随机推荐
- SCI写作经验交流,别人的经验借鉴下,很有用的!
http://www.dxy.cn/bbs/topic/27127771 语言是非英语国家论文的最大障碍.首先是时态和语态:在前言和讨论里,描述该研究的过去历史和现状时,要使用相应的时态:过去就使用过 ...
- ubuntu下安装迅雷
----------------------------------2016-03-28新增适用于ubuntu16.04系列的安装包---------------------------------- ...
- Servlet实现重定向的两种方式
使用Servlet实现请求重定向:两种方式 1. response.setStatus(302); response.setHeader("location", "/Re ...
- php get_magic_quotes_gpc()函数
magic_quotes_gpc函数在php中的作用是判断解析用户提示的数据,如包括有:post.get.cookie过来的数据增加转义字符“\”,以确保这些数据不会引起程序,特别是数据库语句因为特殊 ...
- 梳理一下JS的基本语法
web三层结构来说 结构层:HTML 从语义角度,描述页面结构 样式层:CSS 从审美的角度,美化页面 行为层:JavaScript 从交互的角度,提升用户体验 ...
- GridView CheckBox 全选
GridView CheckBox 全选 <script type="text/javascript"> $(function () { $("#allChe ...
- Dell R710、720等系列类服务器 U盘安装centos6.5 操作系统
一般全新服务器创建系统的时候,没做raid 会报错,如下: 解决: 开机启动时按F10,进入下面界面. 在LC设置-语言和键盘设置选项里可以选择界面显示的语言 在界面主页选项里选择"配置RA ...
- scrum 4.0
1.准备看板. 形式参考图4. 2.任务认领,并把认领人标注在看板上的任务标签上. 先由个人主动领任务,PM根据具体情况进行任务的平衡. 然后每个人都着手实现自己的任务. 3.为了团队合作愉快进展顺利 ...
- Java多线程死锁的产生实例
死锁产生的四个必要条件: (1) 互斥条件:一个资源每次只能被一个进程使用.(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放.(3) 不剥夺条件:进程已获得的资源,在末使用完 ...
- asp.net写验证码
生成验证码与匹配验证码的服务端代码 <%@ WebHandler Language="C#" Class="ValidataeCodeHandler" % ...