首先要理解作用域
- 在JavaScript中,作用域通常是指代码的上下文(context)。能够定义全局或者局部作用域。
- 函数作用域:JavaScript 中函数域为最小域范围。for与while循环或者if和switch都不能构建作用域。规则就是,新函数新域。
- 词汇作用域:当遇到一个函数嵌套到另一函数中,内部函数能够访问外部函数的作用域,那么这种方式叫做词汇作用域(Lexical Socpe)或者闭包,也称为成为静态作用域。
- 任何父作用域中定义的变量、对象和函数在其域作用链中都可以使用
- 作用域链:函数的作用域由作用域链构成。我们知道,每个函数可以定义嵌套的作用域,任何内嵌函数都有一个局部作用域连接外部函数。这种嵌套关系我们可以称为链。域一般由代码中的位置决定。当解释(resolving)一个变量,通常从作用域链的最里层开始,向外搜索,直到发现要寻找的变量、对象或者函数。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链包含了在环境栈中的每个执行环境对应的变量对象。通过作用域链,可以决定变量的访问和标识符的解析。全局执行环境的变量对象始终都是作用域链的最后一个对象。
闭包
特性:
- 函数嵌套函数
- 函数内部可以引用外部的参数和变量
- 参数和变量不会被垃圾回收机制回收
作用:创建私有变量模仿块级作用域
闭包是指有权访问另一函数作用域中的变量的函数。换句话说,在函数内定义一个嵌套的函数时,就构成了一个闭包,它允许嵌套函数访问外层函数的变量。通过返回嵌套函数,允许你维护对外部函数中局部变量、参数、和内函数声明的访问。这种封装允许你在外部作用域中隐藏和保护执行环境,并且暴露公共接口,进而通过公共接口执行进一步的操作。
闭包和词法域( Lexical Scope)很像。返回函数引用,这种实际应用,是一个可以用来解释闭包工作原理的好例子。在我们的域内部,我们可以返回对象,能够被父域使用
闭包使得我们的内部域无法被公共域访问到。单独调用函数并不作任何操作,因为其单纯的返回一个函数。闭包并不一定需要返回函数。单纯在中间词汇域量的范围外简单访问变量就创造了一个闭包。
闭包的应用
模块化:模块类似于一个单例对象。由于在上面的代码中我们利用了(function() { ... })();的匿名函数形式,因此当编译器解析它的时候会立即执行。在闭包的执行上下文的外部唯一可以访问的对象是位于返回对象中的公共方法和属性。然而,因为执行上下文被保存的缘故,所有的私有属性和方法将一直存在于应用的整个生命周期,这意味着我们只有通过公共方法才可以与它们交互。
立即执行的函数表达式(IIFE): 是一个在全局环境中自执行的匿名函数,护全局命名空间免受变量污染,它通过构建函数作用域的形式将变量与全局命名空间隔离,并通过闭包的形式让它们存在于整个运行时(runtime)。在很多的应用和框架中,这种封装源代码的方式用处非常的流行,通常都是通过暴露一个单一的全局接口的方式与外部进行交互。