js闭包是什么?

1、闭包是什么?

  闭包(closure)就是可以读取其余函数内部变量的函数。在javascript中,只有函数内部的子函数才能读取局部变量,因此闭包能够理解成 “定义在一个函数内部的函”。在本质上,闭包是将函数内部和函数外部链接起来的桥梁。(闭包的最典型的应用是实现回调函数(callback) )。javascript

2、JS中闭包的优缺点及特性

  → 优势:

    1.保护函数内的变量安全
    2.在内存中维持一个变量(用的太多就变成了缺点,占内存) ;
    3. 逻辑连续,当闭包做为另外一个函数调用的参数时,避免你脱离当前逻辑而单独编写额外逻辑。
    4. 方便调用上下文的局部变量。
    5. 增强封装性,能够达到对变量的保护做用。java

  → 缺点:

    1.常驻内存,会增大内存使用量,使用不当很容易形成内存泄露。
    2.还有有一个很是严重的问题,那就是内存浪费问题,这个内存浪费不只仅由于它常驻内存,更重要的是,对闭包的使用不当会形成无效内存的产生。jquery

  → 特性:

    1. 函数嵌套函数
    2. 内部函数能够访问外部函数的变量
    3. 参数和变量不会被回收。web

3、变量做用域

  要理解闭包,仅理解上边关于闭包的概念是不行的。首先要理解javascript的特殊的变量做用域。
  (1) 变量的做用域无非就两种:全局变量和局部变量。
  (2) javascript语言的特别之处就在于:函数内部能够直接读取全局变量,可是在函数外部没法读取函数内部的局部变量。
  (3)注意点:在函数内部声明变量的时候,必定要使用var命令。若是不用的话,你实际上声明的是一个全局变量!安全

4、用代码诠释闭包

  在Javascript中闭包的建立过程,如如下程序所示。闭包

function a () {
   var i = 0;
   function b () {
      alert (i++);
   }
  return b;
}
var c = a();
c();  //函数调用
  →代码特色

   这段代码有两个特色:
      一、函数b嵌套在函数a内部;
      二、函数a返回函数b。
   这样在执行完var c = a( )后,变量c其实是指向了函数b,再执行c( )后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就建立了一个闭包,这是由于函数a外的变量c引用了函数a内的函数b。也就是说,当函数a的内部函数b被函数a外的一个变量引用的时候,就建立了一个闭包。 框架

  → 做用

     简而言之,闭包的做用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制不会收回a所占用的资源,由于a的内部函数b的执行须要依赖a中的变量。
     在上面的例子中,因为闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。
     那么咱们来想象另外一种状况,若是a返回的不是函数b,状况就彻底不一样了。由于a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引 用,所以函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被回收。svg

  →应用场景

      一、保护函数内的变量安全。函数a中i只有函数b才能访问,而没法经过其余途径访问到,所以保护了i的安全性。
      二、在内存中维持一个变量。因为闭包,函数a中i的一直存在于内存中,所以每次执行c(),都会给i自加1。函数

5、如何从外部读取函数内部的局部变量?

  出于种种缘由,咱们有时候须要获取到函数内部的局部变量。可是,上面(3、变量做用域)已经说过了,正常状况下,这是办不到的!只有经过变通的方法才能实现。那就是在函数内部,再定义一个函数。性能

function demo1 () {
    var n = 6699;
    function demo2 () {
      alert(n); // 6699
    }
  }

  在上面的代码中,函数 demo2 就被包括在函数demo1内部,这时demo1内部的全部局部变量,对demo2都是可见的。可是反过来就不行,demo2内部的局部变量,对demo1就是不可见的。
  这就是Javascript语言特有的”链式做用域”结构(chain scope),
  子对象会一级一级地向上寻找全部父对象的变量。因此,父对象的全部变量,对子对象都是可见的,反之则不成立。
  既然demo2能够读取demo1中的局部变量,那么只要把demo2做为返回值,咱们不就能够在demo1外部读取它的内部变量了吗!

6、闭包的用途

  闭包能够用在许多地方。它的最大用处有两个,一个是前面提到的能够读取函数内部的变量,另外一个就是让这些变量的值始终保持在内存中,不会在demo1调用后被自动清除。
  那为何会这样呢?缘由就在于demo1是demo2的父函数,而demo2被赋给了一个全局变量,这致使demo2始终在内存中,而demo2的存在依赖于demo1,所以demo1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

7、使用闭包的注意点

  (1)因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题,在IE中可能致使内存泄露。解决方法是,在退出函数以前,将不使用的局部变量所有删除。
  (2)闭包会在父函数外部,改变父函数内部变量的值。因此,若是你把父函数看成对象(object)使用,把闭包看成它的公用方法(Public Method),把内部变量看成它的私有属性(private value),这时必定要当心,不要随便改变父函数内部变量的值。

8、总结:

  1. 闭包是指有权访问另外一个函数做用域中的变量的函数,建立闭包的最多见的方式就是在一个函数内建立另外一个函数,经过另外一个函数访问这个函数的局部变量。闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易形成内存泄露。   2. 不适合场景:返回闭包的函数是个很是大的函数。     闭包的典型框架应该就是jquery了。     闭包是javascript语言的一大特色,主要应用闭包场合主要是为了:设计私有的方法和变量。     这在作框架的时候体现更明显,有些方法和属性只是运算逻辑过程当中的使用的,不想让外部修改这些属性,所以就能够设计一个闭包来只提供方法获取。   3. 没必要纠结到底怎样才算闭包,其实你写的每个函数都算做闭包,即便是全局函数,你访问函数外部的全局变量时,就是闭包 的体现。