JS中闭包的理解

什么是闭包?

闭包其实就是一个函数,什么样的函数?能够访问另一个函数作用域中变量的函数。

为什么要有闭包?

在回答这个问题之前,我先提一个假设,我们都知道在内部的函数可以访问外部函数的变量,假设现在就是有这么一个需要,需要外部环境来访问函数的内部变量,怎么办?这时就要用到闭包,这就要牵扯到闭包的实现原理,即作用域链的工作。每当函数创建时,JS底层都会在其执行环境下创建一个作用域链,这个作用域链可以理解为一个指针链表,指向每个函数的活动对象(活动对象中保存着局部变量),并且这个作用域链由内函数向外函数扩散直到全局变量对象。父函数内部返回闭包,在外部环境调用父函数后,这时父函数执行完毕,作用域链销毁,但是父函数的活动对象没有销毁,任然留在内存中,为什么?就是因为我返回的闭包的作用域链中有指向父函数活动对象的引用。这样,在外部环境下,返回的闭包就会沿着自己的作用域链去寻找访问的值,就实现了在外部环境下访问函数的内部变量

闭包与变量的关系

首先先给大家两个简单的代码

function createFunctions(){ 
 var result = new Array(); 
 for (var i=0; i < 10; i++){ 
 result[i] = function(){ 
 return i; 
 }; 
 } 
 return result; 
}

在这段代码中,直观感觉返回的result是一个返回i值的一个函数,结果应该是0-9,但是结果都是10。

在这里我想说两个问题,第一JS没有块级作用域,i变量会被绑定到create函数的活动对象中。第二在执行返回的闭包后,此时沿着作用域链寻找到的 i 值都是10.这个 i 值是createFunctions函数活动对象中保存,0-9都在这个活动对象中出现过,但是最终让10覆盖掉了,所以每一个闭包访问到的 i 都是10.

那么如何修改呢?

function createFunctions(){ 
  var result = new Array(); 
  for (var i=0; i < 10; i++){ 
     result[i] = function(num){ 
         return function(){ 
             return num; 
         }; 
     }(i);
 } 
 return result; 
}
在重写了前面的 createFunctions() 函数后,每个函数就会返回各自不同的索引值了。在这个版本中,我们没有直接把闭包赋值给数组,而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋给数组。这里的匿名函数有一个参数 num ,也就是最终的函数要返回的值。在调用每个匿名函数时,我们传入了变量 i 。由于函数参数是按值传递的,所以就会将变量 i 的当前值复制给参数 num 。而在这个匿名函数内部,又创建并返回了一个访问 num 的闭包。这样一来, result 数组中的每个函数都有自己num 变量的一个副本,因此就可以返回各自不同的数值了。也就是说,这个闭包数组所访问那个匿名函数中的num其实都是来自不同的活动对象,每个活动对象所保存的num值都不同,所以才会返回0-9.

你可能感兴趣的:(JS中闭包的理解)