什么是 闭包
首先我想借用一下某本书中对js闭包的解释:
书中理解: JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里。
我的理解 :闭包就是一个函数把外部的那些不属于自己的对象也包含(闭合)进来了。
简而言之 :JavaScript中的闭包,无非就是变量解析的过程。
为什么需要闭包?
局部变量 无法共享和长久的保存,而 全局变量 可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染。
特点
-
占用更多内存
-
不容易被释放
何时使用?
变量既想反复使用,又想避免全局污染
如何使用?
1.定义外层函数,封装被保护的局部变量。
2.定义内层函数,执行对外部函数变量的操作。
3.外层函数返回内层函数的对象,并且外层函数被调用,结果保存在一个全局的变量中。
函数生命周期
首先看一段话:
每次定义一个函数,都会产生一个作用域链 (scope chain)。当JavaScript寻找变量varible时(这个过程称为变量解析),总会优先在当前作用域链的第一个对象中查找属性varible ,如果找到,则直接使用这个属性;否则,继续查找下一个对象的是否存在这个属性;这个过程会持续直至找到这个属性或者最终未找到引发错误为止 。
看个简单版的例子:
(function(){ var hello="hello,world"; function welcome (hi){ alert (hi); //解析到作用域链的第一个对象的属性 alert(hello); //解析到作用域链的第二个对象的属性 } welcome("It's easy");})();
运行结果很简单,一个弹窗It’s easy.一个弹窗hello,world。
分析过程如下:
对于函数welcome(),定义welcome的时候会产生一个作用域链对象,为了表示方便,记作scopechain。scopechain是个有顺序的集合对象。
-
scopechain的第一个对象:为了方便表示记作sc1, sc1有若干属性, 引用本函数的参数和局部变量 ,如sc1.hi ;
-
scopechain的第二个对象:为了方便表示记作sc2,sc2有若干属性, 引用外层函数的参数和局部变量 ,如sc2.hello;
-
…
-
scopechain的最后一个对象:为了方便表示记作scn, scn引用的全局的执行环境对象 ,也就是window对象!,如scn.eval();
这里之所以可以弹出hello,world,原因就是变量解析时在welcome函数作用域链的第一个对象上找不到hello属性,然后就去第二个对象上找去了(结果还真找到了)。
所以,JavaScript中的所谓的高大上的闭包其实很简单,根本上还是变量解析。而之所以可以实现,还是因为变量解析会在作用域链中依次寻找对应属性的导致的。
闭包就是一个函数引用另外一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点, 不必要的闭包只会徒增内存消耗! 另外使用闭包也要注意变量的值是否符合你的要求,因为他就像一个静态私有变量一样。闭包通常会跟很多东西混搭起来,接触多了才能加深理解,这里只是开个头说说基础性的东西。
总结:
第一,对象的引用,函数也是对象,首先我们要理解js面向对象的思想和原型及引用,a和b是两个对象,b继承了a的原型,如果查询b.x这个属性,可是对象b中没有x这个属性,js就会顺着去a中找x这个属性,这也就是闭包中内部函数访问外部变量的原理。
第二就是js的垃圾回收机制,js的垃圾回收机制很简单,就是当一个变量的生命周期结束就是不用了的时候就会回收,举个例子,如果函数a中嵌套了函数b,a中声明了变量x,函数b访问函数a中的x,因为js中函数是级联执行的,也就是我们说的链式执行,a执行时x进入执行状态,如果不用了的话x就会进入执行完毕状态,这时就会被回收,如果这时候b引用了x变量,相当于x一直处于执行状态,垃圾回收机制就不会回收x,x变量会一直存在内存中,这种方式主要是为了保护私有变量而且可以存储那些不持久型的动态变量。
第三,就是作用域scope,在js中每一个函数都是广义的一个闭包,每个函数除了声明的全局变量剩下的变量都是自己的私有变量,作用域都只限于本函数作用域内,闭包相当于暴露与外的一个接口,可以把私有变量暴露给调用者使用。
最后,闭包是js一大特性,应该合理利用闭包,滥用闭包会造成内存泄漏
相关文章
本站已关闭游客评论,请登录或者注册后再评论吧~