闭包,一直是一个比较让人晦涩难懂的,面试中还经常会被问到,那么到底什么是闭包呢?我们来看一段代码
function fn(){ var a = 1;}console.log(a); // a is not defined
放到浏览器中执行,发现报错了,原因我想大家也都清楚,由于js中作用域的原因,函数外部是无法直接获取函数内部的一些局部变量的,注意我说的是局部变量,如果是全局变量是可以访问的,如下代码
function fn(){ a = 1;}fn();console.log(a); //1
言归正传,那么如果真的有需求需要获取函数中的局部变量,这时候怎么办?那就要用到闭包了
function fn(){ var a = 1; function fn2(){ alert(a); } return fn2;}var f1 = fn();f1(); //1
如上就是一个闭包,可以看到我们已经访问到了fn中的局部变量,当然,不用闭包,用其他的方法也能访问,我们改一下代码
function fn(){ var a = 1; return a;}var f1 = fn();console.log(f1); //1
同样做到了,那么闭包到底有什么用呢?网上查了一些资料也是无解,我就以我的理解来说吧
首先,闭包就是函数嵌套函数,相对于直接return一个变量,闭包可以在被嵌套函数内部做一下逻辑然后再返回,功能更强大
我们再来看一个例子感受一下闭包的好处
<!DOCTYPE html>
<html><head> <meta charset="UTF-8"></head><body> <button>Button0</button> <button>Button1</button> <button>Button2</button> <button>Button3</button> <button>Button4</button></body><script> var btns = document.getElementsByTagName('button'); for(var i = 0, len = btns.length; i < len; i++) { (function(i) { btns[i].onclick = function() { alert(i); } })(i) }</script></html>点击按钮我们就可以得到对应的索引,这用普通的for循环遍历,添加事件是做不到的,闭包为何能做到呢?
这是因为每次循环的i值都被封闭起来,这样在函数执行时,会查找定义时的作用域链,这个作用域链里的i值是在每次循环中都被保留的,因此点击不同的button会alert出来不同的i。
闭包有一个很重要的特点,即是优点也是缺点,那就是变量始终保存在内存中,不会被垃圾回收机制所回收,这也就意味着会造成内存泄漏。所以不能滥用闭包,否则会造成网页的性能问题,解决方法是,在退出函数之前,将不使用的局部变量全部删除。