JS 闭包详解

闭包是可以用作函数参数和方法参数的代码块,是指有权访问另一个函数作用域中的变量的函数。因为在JS中,在另一个函数内部定义的函数会将包含函数的活动对象加到它的作用域链中。
闭包由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。
闭包的用处一是可以读取函数内部变量的值,二是可以让这些变量的值始终保持在内存中。
不过闭包只能取得包含函数中任何变量的最后一个值,所以一般会创建另一个匿名函数强制符合预期

比如,假设我们想要将循环的index放入alert 的function内存入数组中,像下面这么做是不可以的。

for(var i = 0, arr =[]; i<3 ; i++){
  arr.push(function () {alert(i);});
}
arr[0](); // 4

造成结果非预期的原因是,函数在预解释阶段,都被当成字符串存入堆内存,在真正执行的时候才会被拿出来执行。数组中存储的实际上只是指向这个堆内存的指针,i并没有传进去,只有在执行的时候才传进去。
具体说明,就是假设我们相应的funtion(){alert}存在内存空间0XAA中
在循环中的操作无非是 i=0 arr = [0XAA] i++ arr = [0XAA,0XAA] ... i=4 时停止循环
当我们执行arr0时调用了 0XAA内的函数,发现当前作用域内没有i,于是向上层函数检索,发现i=4。所以无论执行哪一项都是4.

如果想要预期结果,需要创建另一个匿名函数

for(var i = 0, arr =[]; i<3 ; i++){
  arr.push(
    (function(i){
      return function() {alert(i);};
    }) (i)
  );
}
arr[0]() //0

现在我们的0XAA地址里存储的变成了一个自执行函数(顺便插播一嘴自执行函数。因为JS语言括号内不能包含语句,所以当解释器扫描到其内部的function时会将其解析为函数表达式,实际上这种方式和我们平时调用函数使用的方式是一样的),其形参赋值i=0,将立刻执行 return function() {alert(i);},我们假设这个函数function() {alert(i);}现在存放在0XA1
其过程就是 i=0 arr=[0XAA(0)] 即 arr = [0XA1] 后面同理
最后调用arr0 时发现当前作用域没有i,于是向上层作用域寻找发现当时作为形参的i是0,最后返回。

这里就是通过立即执行函数赋值,通过 return 一个function 这种 闭包来延长对该值的引用。

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