JS闭包(函数)

935 阅读2分钟

Js闭包函数是什么?

闭包是指有权访问另一个函数作用域中的变量的过程。我们称调用的这个函数是外部函数,其返回的函数是内部函数,但是问题来了,正常的情况下,一个函数调用结束时,其内部定义的变量会被销毁。但是如果说函数返回函数,这个被返回的函数中引用了其外部函数中定义的变量,那么这个时候这些变量是会以某种方式被保存起来供内部函数引用,这种情况下就会形成函数闭包

举个例子

要求:

有五个按钮,我们每点击某个按钮一次这个按钮可以记录点击的次数,每点击一次就+1

如何实现?

第一步,肯定先写结构样式了,当然css样式请君自行改进😂

/*html结构*/
<body>
 <button>点击次数:0次</button>
 <button>点击次数:0次</button>
 <button>点击次数:0次</button>
 <button>点击次数:0次</button>
 <button>点击次数:0次</button>
</body>

未使用闭包实现

//获取所有的按钮
    var btns = document.querySelectorAll("button");
// for循环遍历所有按钮
    for (var i = 0; i < btns.length; i++) {
// 为每个按钮添加一个自定义属性index索引
      btns[i].index = i;
//定义numclck记录点击次数
      var numclck = 0;
// 点击事件
      btns[i].onclick = function () {
        numclck++;
// this.index  当前点击的这个按钮,通过索引index得到
        btns[this.index].innerHTML = `点击次数:${numclck}次`;
      }
    }

我们发现可以实现我们要求的效果,当然这里我们也可以用ES6新增的关键字let来声明我们的变量i,我们来试一下

/*可以发现代码是不是少了很多,为什么呢?可已看下我发的let、const、var的区别那篇文章你就会明白*/
var btns = document.querySelectorAll("button");
    for (let i = 0; i < btns.length; i++) {
      let numclck = 0;
      btns[i].onclick = function () {
        numclck++;
        btns[i].innerHTML = `点击次数:${numclck}次`;
      }
    }

使用闭包来实现

 //获取所有的按钮元素
    var btns = document.querySelectorAll("button");
    for (var i = 0; i < btns.length; i++) {
      //这里的i为自执行函数(Q2:是什么?)的形参  i为局部变量
      (function(i){
        var numclck = 0; //局部变量   因为这块内存空间没有被销毁,所以存在numclck和i的空间有5个,而且他们是独立的。
        btns[i].onclick = function(){
          numclck+=1;//也可以写为numclck++
          btns[i].innerHTML = `点击次数:${numclck}次`;
        }
      })(i) //这里的i是for循环执行时的i,为全局变量,执行了5次
    }

自执行函数是什么(FQ2)

  • 是一个在定义阶段就会立即执行的函数(也叫立即执行函数 IIFE)而且只会执行一次
/*语法   */
 (function(){
        //函数体
      })();

总结

函数中嵌套函数,我们分别称他们为外部函数和内部函数,调用内部函数,内部函数可以使用外部函数的变量。这就是形成闭包函数的过程,使用闭包可以延长我们变量的使用寿命,在有些情况下非常适用。

  var a = "小白";
    function fn(){
      var b = "老黑";
      // 内部函数
      function innerFn(){
        var c = 666;
        console.log(b); //在内部函数innerFn中并没有b但是这里我们可以用外部函数定义的b
      }
      return innerFn;
    }
    var res = fn(); //res指向innerFn
    res();//调用res
    console.log(a)