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()); //19 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中重要概念-闭包-深入理解相关推荐
- 12.在JavaScript中的事件模型如何理解?
一.事件与事件流 javascript中的事件,可以理解就是在HTML文档或者浏览器中发生的一种交互操作,使得网页具备互动性, 常见的有加载事件.鼠标事件.自定义事件等 由于DOM是一个树结构,如果在 ...
- javascript中浅拷贝和深拷贝的理解
javascript中浅拷贝和深拷贝的理解 什么是拷贝? 简单地说就是复制,对数据的复制 浅拷贝:改变拷贝者的值,被拷贝者的值也会变化 深拷贝:改变拷贝者的值,被拷贝者的值不会变化 由于基本数据类型是 ...
- JavaScript中call、apply个人理解
JavaScript中call.apply个人理解 一句话即通俗的说:call.apply 是为了改变this的状态而存在的 var lisi = {name:'李四',age:23};var zs ...
- JavaScript中的作用域,闭包和上下文
深入理解JavaScript中的作用域和上下文 很多语言当中都会有作用域的概念,它会给我们带来便利,偶尔也会有烦恼,只有清楚地理解和掌握了它,才能更好地为我所用,今天就带来这么一篇文章供大家参考. 介 ...
- javascript 中的暗物质 - 闭包
1. 诡异的闭包 javascript 中有一个特殊的特性 - 闭包,对于 .NET 程序员来说,比较熟悉的是面向对象的程序设计 OOP, 而来自函数式语言的闭包则显得比较诡异,许多程序员对它敬而远 ...
- javascript匿名函数及闭包深入理解及应用
1.匿名函数 函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数:就是没有函数名的函数. 1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式 第一种: ...
- 对javascript中的匿名函数的理解
(function(){//这里的所有变量和函数都属于局部对象 }()); 在javascript中以function开头的语句通常是函数声明.加上了外面的括号(黄色背景)后则创建的是函数表达式. 蓝 ...
- JavaScript中加号运算符+ 运算过程理解
在JavaScript中二元加法运算符"+"可以对两个数字或者字符串进行连接操作. 1+2=>3 "hello"+" "+" ...
- javascript中 __proto__与prorotype的理解
我们先看看这样一段代码: 1 <script type="text/javascript"> 2 var Person = function () { }; 3 var ...
最新文章
- 植物MWAS研究—小米产量与微生物组关联分析
- go dll 传char*
- ITK:将itk :: Image转换为vtkImageData
- 2pc_two phase commit详情
- 第一次正经面试之发现自己的缺陷和不足
- cam350 不能打开光绘文件_如何在CAM350中导入Allegro光绘
- 13--长度最小的子数组
- c语言辗转相除法求最大公约数_趣味探究:妙法求“最大公因数”,比书上难一点,你敢挑战吗?(适合56年级)...
- 【Android】11.3 屏幕旋转和场景变换过程中GridView的呈现
- 诺禾致源css客户端,诺禾,诺禾致源:CSS 基础教学
- Android.mk宏定义demo
- 游戏开发之多态及虚函数(C++基础)
- Focal Loss 和 LightGBM 多分类应用-python实现
- Sublime安装使用插件pretty json
- php 支付宝用户信息授权,支付宝登录获取用户信息授权
- 微信小程序注册流程详解
- 手机参数中的4+64G到底是什么?
- 零基础新手如何学习SEO
- Git基础之(三)——时光穿梭机
- mysql之聚簇索引与非聚簇索引
热门文章
- 【Smart_Point】unique_ptr中独占指针使用MakeFrame
- gdb+gdbserver
- ubuntu设置securecrt串口权限
- 【CSDN2012年度博客之星】需要您的一票,感谢大家的支持
- apache的keepalive和keepalivetimeout(apache优化)
- 用ext_skel,实现一个PHP扩展,添加到PHP并调用
- C++中struct的使用
- libcurl库的使用(通过libcurl库下载url图像)
- 图片像素、英寸、厘米之间的单位换算
- 图像空间变换--imtransform