很久前的一个问题终于得以解决,内心是无比喜悦的,不多说,先上代码:

 function test(){
for(var i=0;i<5;i++){
window.onclick=function(){
alert(i);
}
}
}
8 test()

原意是点击第一下弹出i的值0,点击第二下弹出i的值1,一直到第五次点击弹出4。想象是美好的,现实却不按常规出牌,无论点击多少次,alert出来的值都是5。后来接触了js闭包,才知道原来是它搞的鬼。看了不少相关书籍和博客后,发现其实它也没有想象得那么难。

我理解的闭包是可以访其他函数作用域的函数,在js中,通常通过在一个函数内部定义另一个函数来实现,如上例。提到闭包,应首先理解JavaScript特有的链式作用域,即一个函数作用域链的第一位是该函数本身的活动对象,第二位是包含该函数(即父函数)活动对象的索引,第三位是父函数的父函数活动对象的索引,以此类推,直至全局变量对象。注意,反之不成立,即父函数的作用域不包含子函数变量对象的索引。如图:

  在文章开头的例子中,每个匿名函数(循环了五次,相当于五个匿名函数)的作用域链中都保存着test的活动对象,所以它们引用的是同一个变量i。当函数返回后,i的值是5,此时,每个函数都引用着保存变量i的对象,所以在每个函数内部,i的值都是5.

闭包具有两面性,有缺点,也有优点,在上例中因为对闭包使用不当没有达到想要的效果,但在一些特殊的应用中,只有用闭包才能实现相应的功能,接下来,就谈谈闭包的用途(优点)和注意事项(缺点)。

  1、用途

  •   从外部读取某个函数的局部变量。

    子函数可以访问父函数的作用域,那么如果全局作用域需要访问函数的局部变量怎么办?

function myA(){
var a=6;
function myB(){
alert(a);
}
return myB;
}
var result=myA();
result();

    在上述代码中,无法直接访问myA内的变量a,但是可以再内部定义一个函数myB,该函数可以访问它的父函数myA的作用域内的变量a,然后将这个函数返回并赋值给result,相当于在全局作用域内调用myB。

  •   让某个局部变量始终保存在内存中

  js的内存回收机制是这样的:当调用一个函数时,为它的局部变量对象分配相应的内存空间,一旦调用结束,则收回为它分配的内存。但是这样会有一个bug,即若在函数A内定义了函数B,而B也调用了A内的局部变量x,且B随时可能被全局调用,因为A调用完毕后内存被收回,所以B访问不到x。js的解决办法是,在定义一个函数时,把这个函数和它可能使用到的变量(包括自身变量和父函数的变量),统统一起保存起来,构成一个闭包,即便当父函数调用完毕,这些变量占用的内存也不会被收回。只有当该函数不可能被调用时,才会收回这些内存。

  若需要随时访问某个局部变量,则可以通过该方法,构建一个闭包,让一个局部变量始终保存在内存中。

  2、缺点

  •   占用过多的内存

    上述js的回收机制说明,只要闭包不被销毁,它的作用域链所占用的内存便不能被释放,若过多地、无用地占用内存,对效率和性能极为不利。

  •   内存泄露

    由于IE9之前的版本对JavaScript和COM对象使用不同的垃圾回收机制(因为IE9之前中的部分对象不是原生JavaScript对象,如其中的BOM和DOM就是以c++的COM对象实现的,所以回收机制不同),所以只要在IE9之前版本中涉及COM对象,就会导致循环引用,以至于对象内存不能被收回。具体来说就是,如果闭包的作用域中保存着一个HTML元素,则意味着该元素将无法被销毁,例如:

function f1(){
var e=document.getElementById("top");
element.onclick=function(){
alert(e.id);
};
}

    上述代码为e元素事件创建了一个闭包,即匿名函数,由于匿名函数包含着对f1活动对象的引用,只要匿名函数存在,e元素的引用次数至少为1,因此它占用的内存便永远不会被收回(IE9对COM对象的垃圾回收机制决定的)。该问题也有相应的解决方法,请读者自行思考。

  最后,关于闭包中this对象,需注意,由于匿名函数的作用域具有全局性,所以慎用闭包的this对象。没有用var声明的局部变量也具有全局性。

js闭包之我见的更多相关文章

  1. javascript作用域和闭包之我见

    javascript作用域和闭包之我见 看了<你不知道的JavaScript(上卷)>的第一部分--作用域和闭包,感受颇深,遂写一篇读书笔记加深印象.路过的大牛欢迎指点,对这方面不懂的同学 ...

  2. js闭包的作用域以及闭包案列的介绍:

    转载▼ 标签: it   js闭包的作用域以及闭包案列的介绍:   首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...

  3. 大部分人都会做错的经典JS闭包面试题

    由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...

  4. Js闭包常见三种用法

        Js闭包特性源于内部函数可以将外部函数的活动对象保存在自己的作用域链上,所以使内部函数的可以将外部函数的活动对象占为己有,可以在外部函数销毁时依然存有外部函数内的活动对象内容,这样做的好处是可 ...

  5. js闭包之初步理解( JavaScript closure)

    闭包一直是js中一个比较难于理解的东西,而平时用途又非常多,因此不得不对闭包进行必要的理解,现在来说说我对js闭包的理解. 要理解闭包,肯定是要先了解js的一个重要特性, 回想一下,那就是函数作用域, ...

  6. (原创)JS闭包看代码理解

    <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...

  7. js闭包理解

    js闭包的作用是使函数外可以访问函数内部的变量,是通过 在函数内部 定义 访问函数内变量 的函数实现的,内部的一个函数产生一个闭包 function a() { var i=0; return fun ...

  8. js闭包理解实例小结

    Js闭包 闭包前要了解的知识  1. 函数作用域 (1).Js语言特殊之处在于函数内部可以直接读取全局变量 <script type="text/javascript"> ...

  9. Js闭包的用途

    本来想总结一点JavaScript中的闭包的一些用法,在查资料的时候发现了一篇很好的文章,就转过来收藏了,下面附上传送门: js闭包的用途 ---------sunlylorn 我们来看看闭包的用途. ...

随机推荐

  1. APP自动化测试怎么测?

    一般来说工具还有技术都是千篇一律 测试测到最后还是业务能力...

  2. msys2 git status显示中文文件名问题

    git config [--global] core.quotepath off https://stackoverflow.com/questions/5854967/git-msysgit-acc ...

  3. DB2自增长ID

    建议类似的应用采用sequence对象,将来的应用维护和数据迁移会很方便.考虑的因素较少. 对于序列可以使用nextval和prevval来获得下一个和上一个值:CREATE SEQUENCE seq ...

  4. 2018.09.11 poj1845Sumdiv(质因数分解+二分求数列和)

    传送门 显然需要先求出ab" role="presentation" style="position: relative;">abab的所有质因 ...

  5. 人体感应模块控制LCD1602背景灯是否开启

    /* Web client This sketch connects to a website (http://www.google.com) using an Arduino Wiznet Ethe ...

  6. 20155218 2016-2017-2 《Java程序设计》第6周学习总结

    20155218 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 Java将输入/输出抽象化为串流,数据有来源及目的地,衔接两者的是串流对象. dump()方 ...

  7. webuploader传递参数

    实际开发过程中,比如我有个工单提交系统,提交工单的时候用webuploader上传图片,如果工单的ID是自增长类型的,那么我在上传图片的时候肯定需要关联上工单的id,这时候就需要通过webupload ...

  8. 201709013工作日记--static理解 && abstract

    1.关于viewHolder设置成static的讨论 一般情况下是尽量不要使用static关键字,因为static一旦有引用变量指向了变量,使用完毕后而没有设置null,就会造成内存泄露,而且很难排查 ...

  9. Global Mapper

    https://blog.csdn.net/mrib/article/details/75116373 http://www.bluemarblegeo.com/products/global-map ...

  10. mybatis操作数据库

    导入jar包 共13包 注意:mysql-connction的版本是5.1.7版低版本可能不行 2.编写配置文件 a. 配置连接数据库的文件 a.1创建数据库 user表 a.2配置文件目录 a.2. ...