与闭包相关的问题

感觉js闭包可以引发一系列面试中比较常考的问题,打算单独写一篇文章加以总结


  1. 如果之前对作用域的相关知识点了解的话,闭包的概念也就非常好理解了。

    闭包是指一个可以访问另外一个函数作用域中的变量的函数(定义在函数内部的函数)。
    作用大概就是形成块级作用域以及私有变量。

    这是我觉得比较通俗易懂的解释。当然es6中的let声明变量可以完美解决块级作用域的问题。

  2. 说到闭包就不得不说到作用域,在JS中,函数的可以允许嵌套的。即,在一个函数的内部声明另一个函数。以这篇博客的代码为例:

    function A(){
      var  a=1;
       function B(){  //在A函数内部,声明了函数B,这就是所谓的函数嵌套。
             var b=2;   
       }
    }
    

    对于A来说,A函数在执行的时候,会创建其A函数的作用域, 那么函数B在创建的时候,会引用A的作用域,类似下面这样

    与闭包相关的问题_第1张图片
    A的作用域

    函数B在执行的时候,其作用域类似于下面这样:

    与闭包相关的问题_第2张图片
    B的作用域

从上面的两幅图中可以看出,函数B在执行的时候,是会引用函数A的作用域的。所以,像这种函数作用域的嵌套就组成了所谓的函数作用域链。当在自身作用域内找不到该变量的时候,会沿着作用域链逐步向上查找,若在全局作用域内部仍找不到该变量,则会抛出异常。

  1. 闭包所引起的问题,看下面的这道例子:

    var funB,
    funC;
    (function() {
      var a = 1;
      funB = function () {
        a = a + 1;
        console.log(a);
      }
      funC = function () {
        a = a + 1;
        console.log(a);
      }
    }());
    funB();  //2
    

    我们可以看到,变量a被“污染”了,意思就是说,对于 funB和funC两个闭包函数,无论是哪个函数在运行的时候,都会改变匿名函数中变量a的值,这种情况就会污染了a变量。

    两个函数的在运行的时候作用域如下图:

    与闭包相关的问题_第3张图片
    闭包引起的变量污染问题

这这幅图中,因为funB和funC与变量a在同一作用域,所以变量a可以被函数funB和funC改变,就相当于外部作用域链上的变量对内部作用域来说都是静态的变量。

所以,为了解决这种变量的污染问题---而引入的闭包的另外一种使用方式。

思想就是:既然外部作用域链上的变量时静态的,那么将外部作用域链上的变量拷贝到内部作用域不就可以啦!! 具体怎么拷贝,当然是通过函数传参的形式啊。

这里就再次用到立即执行函数了,修改后的代码如下:

var funB,funC;
(function () {
  var a = 1;
  (function (a) {
    funB = function () {
      a = a + 1;
      console.log(a);
    }
  }(a));
  (function (a) {
    funC = function () {
      a = a + 1;
      console.log(a);
    }
  }(a));
}());
funB()||funC();  //输出结果全是2 另外也没有改变作用域链上a的值。

在函数执行时,内存的结构如图所示:

与闭包相关的问题_第4张图片
在外面加一层自执行函数

由图中内存结构示意图可见,为了解决闭包的这种变量污染的问题,而加了一层函数嵌套(通过匿名函数自执行)

类似的问题还可以参考这篇博客:用立即执行函数 解决闭包问题

你可能感兴趣的:(与闭包相关的问题)