所谓闭包

所谓闭包

Closures (闭包)是使用被作用域封闭的变量,函数,闭包等执行的一个函数的作用域。通常我们用和其相应的函数来指代这些作用域。(可以访问独立数据的函数)
闭包是指这样的作用域,它包含有一个函数,这个函数可以调用被这个作用域所封闭的变量、函数或者闭包等内容。通常我们通过闭包所对应的函数来获得对闭包的访问。-----闭包-MDN

上面是MDN对闭包的定义,可以理解为:闭包是 JS 函数作用域的副产品。
换句话说,正是由于 JS 的函数内部可以使用函数外部的变量,所以正好符合了闭包的定义,而非JS 故意要使用闭包。

所以只要你懂了 JS 的作用域,你自然而然就懂了闭包,即使你不知道那就是闭包!

下面我们通过一个经典面试题来分析一下

for (var i = 0; i < spans.length; i++) {
   spans[i].onclick = function() {
       alert(i);
   }
}

上面代码在页面加载后就会执行,当i的值为4的时候,判断条件不成立,for循环执行完毕,但是因为每个span的onclick方法这时候为内部函数,并没有执行,这里的i是全局变量,i被引用,内存不能被销毁,i的值会一直保持4,直到程序改变它或者所有的onclick函数销毁(主动把函数赋为null或者页面卸载)时才会被回收。

这样每次我们点击span的时候,onclick函数会查找i的值(作用域链是引用方式),一查等于4,然后就alert给我们了。而下面这种方式是使用了一个立即执行的函数又创建了一层闭包,这时候把i当参数传入,函数立即执行,num保存每次i的值,这里的num是这个立即执行函数的私有变量。所以 这里每次点击会弹出不同的值,

for (var i = 0; i < spans.length; i++) {
  !function(num) {
      spans[i].onclick = function() {
          alert(num);
      }
  }(i);
}

作用域

JS语言的特别之处就在于:函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。
*注意点:在函数内部声明变量的时候,一定要使用var命令。

关于作用域的详细知识可以参见我的另外一篇文章----函数与作用域

闭包的作用

  1. 让你在一个局部变量作用域之外也可以访问到这个局部变量!!如下代码就可以实现在fn外部访问变量a,
  2. 另一个作用就是让这些变量的值始终保持在内存中,不会在函数调用后被自动清除。比如下面的代码中的fn调用执行后,变量a并没有被浏览器的垃圾回收机制(garbage collection)回收。
function fn() {
  var a = xxx;
  return function (){
    return a;
  }
}

有人会说这就造成了内存泄露

错!!!这个问题本身就有问题,内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。

闭包里面的变量明明就是我们需要的变量,凭什么说是内存泄露?比如刚刚的代码中的变量a!!!

这个谣言是如何来的?

因为 IE。IE 有 bug,IE 在我们使用完闭包之后,依然回收不了闭包里面引用的变量。

你可能感兴趣的:(所谓闭包)