首页 > 代码库 > js闭包
js闭包
前两天去面试,被面试官问到平常写关于什么方面的闭包知识,顿时有点懵逼,虽然知道闭包是个大概什么概念,但是在平常的工作中,貌似用的真的比较少,这几天通过翻阅书籍,就想着来写一篇关于闭包的文章,了解得比较浅,希望看到的大神可以多多指点。
1.什么是闭包
闭包也就是指可以访问其他函数作用域中变量的函数,通常创建闭包的方式就是在一个函数内创建一个函数。
2.闭包的特性
闭包主要有以下三个特性:
1.函数嵌套函数
2.函数内部可以访问内部的参数和变量
3.被访问的参数和变量不会被垃圾回收机制回收。
3.变量作用域
想要更好地理解闭包,就不得不理解js作用域和作用域链的概念。
js中的变量不外乎两个:全局变量和局部变量;
js语言的特点就是函数内部可以访问全局中定义的变量,但是函数外部却不能访问函数内部定义的局部变量
例1:var global = ‘global’; //定义一个全局变量
function test1(){
console.log(global);
};
test(); //输出 global
例2:
注:js没有块级作用域的概念,只有函数作用域
4.如何从外部读取内部变量?
由于js语言作用域的特点,一般情况下,我们是没有办法获取局部变量的值。但是在实际的应用中,我们有时候需要访问内部变量,这个时候闭包就派上用场了。
例:
这样我们就可以访问到函数内部定义的局部变量 ,函数test3返回的匿名函数就是一个闭包。
5.使用闭包的好处
那么使用闭包到底有什么好处呢,闭包的好处有以下几点:
1.使一个变量长期驻扎在内存中
2.避免全局变量的污染
3.私有成员的存在
一.变量长期驻扎在内存中
例:
解析:以上代码的解析结果,可以看出,局部变量a在函数test4()执行完毕后,并没有直接被销毁,而是一直驻扎在内存中。
二.模块化代码,减少全局变量的污染
例:
解析:将匿名函数的返回值直接赋值给test5变量,然后执行这个变量。
三.私有成员的存在
诸如Java在内的一些语言,支持把方法声明为私有的,即只能被同一个类中的其他方法调用,就是不支持这样的原生机制,但是可以通过闭包的方式进行模拟私有方法。
例:
6.在循环中使用闭包:一个常见的错误
有时候会遇到在一个li列表中,点击相应的li元素弹出其相应的index值。
例:
在浏览器中运行,会发现不论点击哪个li,都只会弹出3,而不是其对应的index值,
该问题的蛀牙原因是赋值给li的onclick事件的是闭包函数而不是闭包对象,在 onclick
的回调被执行时,循环早已经完成。
运用另外一种方法可以解决这个问题,
7.性能考量
在不是非得使用闭包的情况下,建议不要使用闭包,因为闭包多脚本性能有影响,同时会消耗大量的性能。
8.内存泄漏
如果闭包的作用域中保存着对HTML元素,那就意味着改元素无法被销毁。
例:function assignHandler(){
var element = document.getElementById(‘id‘);
element.onclick = function(){
console.log(element.id);
}
}
解析:以上代码创建了一个作为element元素的事件处理程序的闭包,而在这个闭包内部又对改元素进行了引用。由于匿名函数保存了对assignHandler()的函数对象的引用,所以对于element变量的引用至少为1,所以该变量会一直存在在内存中,不会被回收。可以通过改写一下:
function assignHandler(){
var element = document.getElementById(‘id‘);
var id = element.id;
element.onclick = function(){
console.log(id);
};
element = null;
}
通过将element.id 的一个副本保存在一个变量中,并在闭包中使用消除了循环引用,必须要记住:闭包会引用包含函数的整个活动对象,而这个活动对象中包含element。即使闭包不引用,但是包含函数的活动对象也会保持着对其的引用,所以有必要将其设置为null。
js闭包