闭包
函数 和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。也就是说,闭包可以让你从内部 函数 访问外部 函数 作用域。在 JavaScript 中,每当 函数 被创建,就会在 函数 生成 时 生成 闭包。
由于闭包的概念比较抽象,所以本篇幅会有较多的主观理解。
在作用域相关的 内容 中可以知道,全局下的作用域想访问 一个 函数 内部的作用域是办不到的,但是 闭包 的特性可以突破这一限制。
每个 函数 都会形成 一个 闭包。
1. 什么是闭包
闭包可以理解成,保留了 函数 作用域链的 一个 环境。
var fn = function ( ) { var number = ; } ; fn ( ) ; console . log ( number ) ;
这个例子是访问不到 number 的,想访问到就可以借助闭包的特性。
var fn = function ( ) { var number = ; return function ( ) { number ++ ; console . log ( number ) ; } ; } ; var increment = fn ( ) ; increment ( ) ; increment ( ) ; increment ( ) ;
这里的 fn 函数 返回了 一个 函数 , 在这 个返回的 函数 所形成的闭包环境就拥有访问上一层作用域的能力,所以每次在 调用 fn 返回的 函数 时,就可以累加 number 。
借助 一个 函数 形成的闭包环境作为跳板,来访问另 一个 函数 的作用域,就是闭包最常见的使用场景。
网络上有许多文献把闭包称为 能访问其他 函数 内部变量的 函数 ,这样理解可能更容易一些。
函数 用到了上层作用域的变量,所以这些变量会在内存中被保留,不会被释放,一些旧的浏览器在内存管理上没有现代浏览器完善,大量的闭包可能会导致 页面 卡顿,不过通常业务开发,会先考虑 效果 ,再考虑 性能 。
2. 闭包的应用
2.1 模拟私有 属性
在 JavaScript 中是没有私有 属性 特性的,利用闭包来隐藏变量,就可以模拟出私有 属性 的 效果 。
var counter = ( function ( ) { var count = ; return { increment : function ( ) { count ++ ; return count ; } , zero : function ( ) { count = ; return count ; } , get value ( ) { return count ; } , } ; } ) ( ) ; counter . increment ( ) ; console . log ( counter . value ) ; // 输出 :1 counter . increment ( ) ; console . log ( counter . value ) ; // 输出 :2 console . log ( counter . count ) ; // 输出 :undefined
这里的自执行匿名 函数 返回 一个 对象,对象中的 方法 就具有访问上层 函数 中的变量的能力,所以他们都能访问 count。
因为 count 不会被释放,所以可以当作 一个 属性 来使用。
2.2 回调 函数 几乎都用到了闭包的特性
回调 函数 通常会用到上层作用域的变量,然后在某一情况下进行 调用 。
var fn = function ( cb ) { console . log ( '异步操作开始' ) ; setTimeout ( function ( ) { console . log ( '异步操作结束' ) ; cb ( ) ; } , ) ; } ; var obj = { flag : false , } ; fn ( function ( ) { obj . flag = true ; console . log ( obj ) ; } ) ;
很明显,这里的回调 函数 就是用到了闭包的特性。
所以闭包其实很常用,结合日常的这些场景能更好的理解闭包。
3. 小结
每个 函数 都有闭包,闭包可以访问到这个 函数 所在的上层作用域,利用这一特性,就能访问到 一个 函数 作用域下的变量。
大量的闭包可能会造成 性能 问题,不过现在的计算机处理器、内存已经让开发者不太需要关注这方面的问题,但在设计 一个 会被大量应用的库和框架时,应当做这方面的考虑,因为 用户 的环境千变万化。
变量提升 ? ?作用域声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did92445