【技术杂货铺】JS中的闭包是个什么东西

  我自己想要了解到闭包这个概念是因为在上一篇随笔,介绍防抖和节流的时候,有一段代码看得我有点犯迷糊,如下

function debounce(fn, delay) {
  var timer = null;
  return function() {
    if (timer) clearTimeout(timer);
    timer = setTimeout(function() {
      fn();
    }, delay);
  }
}

  按照我之前的了解,每次调用这个debounce防抖函数的时候,timer都要被重新赋值为null,这怎么起得到定时器的作用呢?后来了解到这是因为闭包的存在,所以timer这个变量在内存一直保存下来,而不是重新清空。好了,下面正式介绍闭包就能知道我在唠叨什么了。

  要说清楚这个问题,我觉得要先从基础说起,并且清楚里面的一些细节,才能理解清楚。js的变量分为全局变量和局部变量。

  全局变量:可以在任意位置访问的变量就是全局变量。例如下面的age。

var age = 10;
function a(){
    console.log(age);  //输出为10  
}

  局部变量:函数中用var定义的变量,只能在函数中访问这个变量,函数外部访问不了。

function a(){
   var age = 10;
}
a();
console.log(age); //Uncaught ReferenceError: age is not defined

  OK,上面这些大家应该都是很熟悉的了,那么有两个注意点要注意,

  1.在函数中如果不适用var定义变量那么js引擎会自动将该变量变为全局变量。

  2.全局变量自创建起就一直保存在内存,直到你关闭页面,而局部变量是当其所在的函数运行完后就会销毁,假如再次调用该函数,会再次重新创建这个变量,即运行完就销毁,回到最初的状态。

  再来说说函数,一个函数可以套很多别的函数,函数里面的子函数可以访问到它上级函数定义的变量,这个上级可以像冒泡一样,一直往上找,如果找到全局变量都找不到,那么就会报错。

  闭包

  下面要通过一个例子来引入闭包

function a(){
    var count = 0;
    console.log(++count);  
}
a(); //输出1
a(); //还是输出1

  上面的代码输出了两个1,是因为上面的局部变量在函数执行完一次后就会销毁,不会保存在内存,再次调用时会重新创建那个变量。那么问题来了,我们怎样做才能确保第一次的创建的变量不会被销毁呢,就是说,如果让第二次调用该函数时,输出的是2,不是1呢?这就需要我们的闭包出来了。

  Warning:JavaScript中有回收机制,函数没有被引用执行完以后这个函数的作用域就会被销毁,如果一个函数被其他变量引用(重要),这个函数的作用域将不会被销毁,(简单来说就是函数里面的变量会被保存下来,你可以理解成全局变量。)

  好了,下面请出我们的闭包:

function a(){
    var count = 0;
    function b(){
        count ++;
        console.log(count);
    }
    return b;
}
var ab = a();
ab(); //输出1
ab(); //输出2

  这里可以看到,里面的变量count的值并没有重新计算,因为函数a被外部的变量ab引用,所以变量count没有被回收。

  如果某个函数被它的父函数之外的一个变量引用,就形成了一个闭包。

  还有一种更为常用的闭包写法:

var ab = (function(){
    var count = 0;
    function b(){
        count++;
        console.log(count);
    }
    return b;
})();

ab(); //1
ab(); //2
ab(); //3

  执行过程分析:首先把一个自执行函数赋值给了ab,这个自执行函数运行完后ab的值就变为了

function b(){
        count++;
        console.log(count);
    }

  因为我们在上面的代码return回去了b,表示将b赋值给了ab,然后因为这个自执行函数被ab引用所以里面的count变量并没有因为这个自执行函数执行完而销毁,而是保存到了内存中,所以多次打印会累加。

posted @ 2021-06-30 16:18  leehwayou  阅读(71)  评论(0)    收藏  举报