美文网首页
谈一下对闭包的理解

谈一下对闭包的理解

作者: VinSmokeW | 来源:发表于2020-04-15 11:49 被阅读0次

一、什么是闭包

闭包是通过改变JS回收机制保留某段作用域的一种手段。当一个函数执行完毕后,里面的局部变量是会被JS自带的垃圾回收机制给销毁的,从而释放内存。但是如果返回一个函数,而且函数里面有用到父级数声明的变量,那么此时,变量不会被回收,因为还有可能被用到,并且外界可以通过函数访问这段作用域下的变量。

例一:

  function foo(){ 
      var a = "我是foo里面的a"; 
  } 

  foo();

这段代码执行后,其实a已经不存在了,因为foo执行完了之后foo的作用域消失了,所以作用域里面的变量不见了,被销毁了。在JS中存在自动垃圾回收,对不需要的变量或者没有使用的作用域进行定期清理。当foo执行完,函数内部的变量a没有在此作用域下任何地方再被引用,所以a变量的作用域会被JS内置垃圾收集器回收。

那么,我们需要用某种方法来获得foo里面的a,怎么办呢?

例二:

 function foo(){
  var a = "我是foo里面的a"; 
   return a;//将变量a给return出来 
} 
let b = foo();//此时b就获得foo里面的a了。

此时,a是不是就获得了呢?并没有,我们得到的只是a的副本,假设我以某种方法修改了a的值,b不会发生任何变化。所以,我们并不是使用的foo内部的a。既然直接返回a不行,那么我们试试返回一个函数。

例三:

function foo(c){
 var num = c; return function A(){
        num++; return num;
    }
}
 var b = foo(5);//b = A
b();
b();

是不是很奇怪,按道理每次都会返回6呀,怎么会每次叠加呢。其实不然,我们执行的是函数b(从foo返回出来的),并没有重新执行foo,所以也就不会每次给num重新赋值5。至于为什么会变成这种累加的情况呢,这是因为函数foo执行完后,其内部的的A函数里面对num有引用,所以foo的作用域以及变量a被保留在了函数A中,返回给了b。

现在,我们就能在外界通过函数b来访问foo内部的变量num了。这就是闭包,我们通过返回一个函数打通了函数内部与外界的桥梁。

二、闭包的作用

闭包可以解决的一个典型的问题就是循环绑定的问题,由于var声明的变量可以穿透作用域,所以如下的代码会出现问题。

例四:

 <ul class="list">
      <li class="bloc">1</li>
      <li class="bloc">2</li>
      <li class="bloc">3</li>
      <li class="bloc">4</li>
      <li class="bloc">5</li>
 </ul>
  var ali = document.querySelectorAll('.wrap ul li') for(var i = 0,l = ali.length;i < l;i++){
   ali[i].onclick = function(){
        console.log(i)  //5 5 5 5 5
    }
  }

执行上面代码你会发现,当你点击任意li时,都会打印出5。这不对呀,和我们想的不一样呀,按道理点击第几个 li 就会打印出相应的下标呀。这是因为,我们绑定了五次onclik事件,无论你有没有触发后面的的函数,for循环都会执行,当你点击的时候,for循环已经执行完了,i 的值早已经变成了5。var 声明的i能够穿透作用域,每次触发点击事件时,函数内部的 i 也都是5。

那么,我们是不是应该想办法把每次循环时的 i 值保存下来呢,就好像每个点击事件都重新给一个新的 i 值。于是,通过闭包可以保存每次循环的 i 值,请看例子:

  for(var i = 0,l = ali.length;i < l;i++){ 
     ali[i].onclick = (function(j){
        return function(){
           console.log(j) 
         } 
     })(i) 
}

我们通过立即执行函数后返回了一个函数的形式,把每次循环的 i 值通过传参放到了不同的函数中,每个函数都是一个独立的作用域,每个函数都有了各自的i值,互相不影响,现在就如我们期望的一样了,点击第几个li打印出第几个 li 的下标。

最后,很多学了ES6的同学会发现 使用let代替例子中的var可以解决上述内部变量被销毁的问题。 因为ES6中的const和let解决块级作用域的问题,所以类似的问题咱们既可以用let 也可以用闭包,那么上述问题就可以迎刃而解了!

本文转载自:https://www.cnblogs.com/wk-ba/p/10340107.html

相关文章

  • 谈一下对闭包的理解

    一、什么是闭包 闭包是通过改变JS回收机制保留某段作用域的一种手段。当一个函数执行完毕后,里面的局部变量是会被JS...

  • 【js基础修炼之路】— 深入浅出理解闭包

    之前对于闭包的理解只是很肤浅的,只是浮于表面,这次深究了一下闭包,下面是我对闭包的理解。 什么是闭包? 引用高程里...

  • JS进阶系列之闭包(2)

    刚刚总结完作用域链,我觉得很有必要马上对闭包总结一下,因为,之前也写过自己对闭包的理解,那时候只知道,闭包就是可以...

  • 自动闭包/逃逸闭包/非逃逸闭包

    自动闭包、逃逸闭包和非逃逸闭包三个概念有些不好理解,这里按我自己的理解总结一下,不对的地方请指正 一、非逃逸闭包:...

  • 对闭包的理解

    一、变量的分类 1、局部变量和全局变量 注意:声明变量时不使用var,所声明的变量就是全局变量,即使是在函数内部声...

  • 闭包

    写一下个人对闭包的理解和看法。 为什么要用函数闭包呢?第一,使用闭包,可以方便调用上下文的局部变量。内部函...

  • 总结一下对闭包的理解

    闭包:是指有权访问另一个函数作用域中的变量的函数。 在JavaScript中没有块级作用域,是链式作用域结构,子对...

  • 闭包(Closure)

    我对闭包的理解 个人理解 : 闭包就是能够读取其他函数内部变量的函数。使用闭包主要是设计私有的方法和变量 优点:可...

  • Gradle开发-Groovy闭包

    # 闭包 闭包的基础知识 闭包的使用 闭包 this,owner,delegate 的理解 总结 ## 闭包的基础...

  • 闭包

    这个问题也是必问的题目.重在把自己对闭包的理解表达出来.而我对闭包的理解是源于很久之前看阮一峰大师讲的闭包(clo...

网友评论

      本文标题:谈一下对闭包的理解

      本文链接:https://www.haomeiwen.com/subject/xzoqvhtx.html