js闭包

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js闭包相关的知识,希望对你有一定的参考价值。

  前两天去面试,被面试官问到平常写关于什么方面的闭包知识,顿时有点懵逼,虽然知道闭包是个大概什么概念,但是在平常的工作中,貌似用的真的比较少,这几天通过翻阅书籍,就想着来写一篇关于闭包的文章,了解得比较浅,希望看到的大神可以多多指点。

1.什么是闭包

  闭包也就是指可以访问其他函数作用域中变量的函数,通常创建闭包的方式就是在一个函数内创建一个函数。

2.闭包的特性

  闭包主要有以下三个特性:

    1.函数嵌套函数

    2.函数内部可以访问内部的参数和变量

    3.被访问的参数和变量不会被垃圾回收机制回收。

3.变量作用域

  想要更好地理解闭包,就不得不理解js作用域和作用域链的概念。

  js中的变量不外乎两个:全局变量和局部变量;

  js语言的特点就是函数内部可以访问全局中定义的变量,但是函数外部却不能访问函数内部定义的局部变量

  例1:var global = ‘global’; //定义一个全局变量   

    function test1(){
      console.log(global);                  
    };                                   

    test(); //输出 global 

  例2: 

    技术分享

 注:js没有块级作用域的概念,只有函数作用域

4.如何从外部读取内部变量?

  由于js语言作用域的特点,一般情况下,我们是没有办法获取局部变量的值。但是在实际的应用中,我们有时候需要访问内部变量,这个时候闭包就派上用场了。

  例:

  技术分享

  这样我们就可以访问到函数内部定义的局部变量 ,函数test3返回的匿名函数就是一个闭包。

5.使用闭包的好处

  那么使用闭包到底有什么好处呢,闭包的好处有以下几点:

    1.使一个变量长期驻扎在内存中

    2.避免全局变量的污染

    3.私有成员的存在

  一.变量长期驻扎在内存中

    例:

      技术分享

      解析:以上代码的解析结果,可以看出,局部变量a在函数test4()执行完毕后,并没有直接被销毁,而是一直驻扎在内存中。

   二.模块化代码,减少全局变量的污染

     例:

      技术分享

     解析:将匿名函数的返回值直接赋值给test5变量,然后执行这个变量。

   三.私有成员的存在

    诸如Java在内的一些语言,支持把方法声明为私有的,即只能被同一个类中的其他方法调用,就是不支持这样的原生机制,但是可以通过闭包的方式进行模拟私有方法。

    例:

     技术分享

6.在循环中使用闭包:一个常见的错误

  有时候会遇到在一个li列表中,点击相应的li元素弹出其相应的index值。

  例:

  技术分享

  在浏览器中运行,会发现不论点击哪个li,都只会弹出3,而不是其对应的index值,

  该问题的蛀牙原因是赋值给li的onclick事件的是闭包函数而不是闭包对象,在 onclick 的回调被执行时,循环早已经完成。

  运用另外一种方法可以解决这个问题,

  技术分享

7.性能考量

  在不是非得使用闭包的情况下,建议不要使用闭包,因为闭包多脚本性能有影响,同时会消耗大量的性能。

8.内存泄漏

  如果闭包的作用域中保存着对html元素,那就意味着改元素无法被销毁。

  例:function assignHandler(){
      var element = document.getElementById(‘id‘);
      element.onclick = function(){
        console.log(element.id);
      }
    }

  解析:以上代码创建了一个作为element元素的事件处理程序的闭包,而在这个闭包内部又对改元素进行了引用。由于匿名函数保存了对assignHandler()的函数对象的引用,所以对于element变量的引用至少为1,所以该变量会一直存在在内存中,不会被回收。可以通过改写一下:

    function assignHandler(){
      var element = document.getElementById(‘id‘);

      var id = element.id;

      element.onclick = function(){
        console.log(id);
      };

      element = null;
    }

   通过将element.id 的一个副本保存在一个变量中,并在闭包中使用消除了循环引用,必须要记住:闭包会引用包含函数的整个活动对象,而这个活动对象中包含element。即使闭包不引用,但是包含函数的活动对象也会保持着对其的引用,所以有必要将其设置为null。

    

 












以上是关于js闭包的主要内容,如果未能解决你的问题,请参考以下文章

JS闭包的概念

(原创)JS闭包看代码理解

关于JS闭包

js闭包的作用

js闭包

js的闭包