理解Javascript闭包


Posted in Javascript onNovember 01, 2013

闭包是ECMAScript一个很重要的特征,但是却很难用合适的定义来描述它。虽然闭包很难清晰地描述,但是,却很容易创建,或者说,不小心创建。然而,闭包的存在其实是有一定的潜在问题的。为了避免“不小心”地创建闭包,以及更好地利用闭包的优点,有必要理解闭包的机制。

闭包的定义
 
关于闭包,有太多的定义,特别是有一些定义非常抽象,象这个:

A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables.

大致是说闭包是一个表达式,拥有一些自由变量及绑定这些变量的执行环境。这种定义太书面化,反而难以理解。

还有另一个定义:
所有函数都是闭包。这个定义给我很大的迷惑,换句话说,由于Javascript没有块级作用域,因此闭包一般指的是函数(想不出除了函数以外还有哪些方式可以构成闭包)。

这里不想太多讨论函数与闭包的关系,下面给出我认为比较容易理解的定义吧。

首先,闭包的存在是基于作用域链。由于作用域链的机制,所有函数(即使全局函数)都能引用上下文执行环境中的变量(即free variables)。

其次,闭包内部必须有free variables。顺便说下两种变量1. Local variables (bound variables) 2. Non-local variables (free variables)

最后,在其上下文环境结束后仍然存在。即内部函数拥有比它的外部函数更长的生命周期。

 
关于闭包定义的解析
 
关于闭包定义的两点,一直在考虑是不是必须同时满足。

首先,如果闭包内部没有free variables,即是说它没有访问外部的变量,那么就失去了闭包的意义。(除非通过其他闭包改变了行为)因此,我认为free variables是必要条件。

其次,如果函数内部存在free variables,但是当其上下文环境销毁后,它也跟着销毁。可以想象内部函数,虽然访问了其外部函数变量,但是当外部函数执行完后也随之回收。这种情况下,闭包的讨论也没有意义。

 
来看两个例子:

var objectA = (function() {
        var localA = "localA";        innerFn();
              // 单纯的内部函数调用
        function innerFn() {
            localA = "innerChange";
        }
        return {
            getLocalA : function() {
                return "empty";
            }
        };
    })();
    objectA.getLocalA();
    objectA.getLocalA = function() {
        return localA;
    };
    //console.log(objectA.getLocalA()); //error: localA is not defined
 
    var objectB = (function() {
        var localB = "localB";
        return {
            getLocalB : function() {
                return "empty";
            },
            updateGetLocalB : function() {
                this.getLocalB = function() {
                    return localB;
                };
            },
            updateLocalB : function() {
                localB = "changeLocalB";
            }
        };
    })();
    console.log(objectB.getLocalB()); // empty
       // 通过其他闭包改变
    objectB.updateGetLocalB();
    console.log(objectB.getLocalB()); // localB
    objectB.updateLocalB();
    console.log(objectB.getLocalB()); // changeLocalB

闭包的优点和缺点

闭包的优点是闭包内部可以访问到定义它们的外部函数的参数和变量(除了this和arguments)。
闭包主要的问题便是它会保存包含它的函数的作用域,因此比一般函数占用更多的内存空间,因此不宜过度使用闭包。

闭包的应用

闭包最基本的应用场景便是通过保护内部变量从而实现私有,比如模块模式。

Javascript 相关文章推荐
JavaScript库 开发规则
Jan 31 Javascript
url地址自动加#号问题说明
Aug 21 Javascript
一些常用且实用的原生JavaScript函数
Sep 08 Javascript
关于js拖拽上传 [一个拖拽上传修改头像的流程]
Jul 13 Javascript
javascript检查浏览器是否已经启用XX功能
Jul 10 Javascript
JavaScript实现快速排序的方法
Jul 31 Javascript
JavaScript如何获取数组最大值和最小值
Nov 18 Javascript
jQuery窗口拖动功能的实现代码
Feb 04 Javascript
JavaScript解析及序列化JSON的方法实例分析
Jan 04 Javascript
JavaScript学习笔记之基于定时器实现图片无缝滚动功能详解
Jan 09 Javascript
vue下的@change事件的实现
Oct 25 Javascript
js实现动态时钟
Mar 12 Javascript
Javascript 命名空间模式
Nov 01 #Javascript
完美解决AJAX跨域问题
Nov 01 #Javascript
javascript中创建对象的几种方法总结
Nov 01 #Javascript
如何学习Javascript入门指导
Nov 01 #Javascript
js动态设置鼠标事件示例代码
Oct 30 #Javascript
获取非最后一列td值并将title设为该值的方法
Oct 30 #Javascript
eclipse如何忽略js文件报错(附图)
Oct 30 #Javascript
You might like
用PHP连mysql和oracle数据库性能比较
2006/10/09 PHP
php XMLWriter类的简单示例代码(RSS输出)
2011/09/30 PHP
解决phpmyadmin中缺少mysqli扩展问题的方法
2013/05/06 PHP
20个2014年最优秀的PHP框架回顾
2014/10/22 PHP
php获取指定日期之间的各个周和月的起止时间
2014/11/24 PHP
PHP调试函数和日志记录函数分享
2015/01/31 PHP
php实现的美国50个州选择列表实例
2015/04/20 PHP
PHP数据源架构模式之表入口模式实例分析
2020/01/23 PHP
jValidate 基于jQuery的表单验证插件
2009/12/12 Javascript
Node.js中调用mysql存储过程示例
2014/12/20 Javascript
jQuery内容过滤选择器用法分析
2015/02/10 Javascript
原生js实现ajax方法(超简单)
2016/09/20 Javascript
JavaScript实现数组降维详解
2017/01/05 Javascript
nodejs入门教程六:express模块用法示例
2017/04/24 NodeJs
详解webpack es6 to es5支持配置
2017/05/04 Javascript
React Native之prop-types进行属性确认详解
2017/12/19 Javascript
axios发送post请求,提交图片类型表单数据方法
2018/03/16 Javascript
解决Vue+Element ui开发中碰到的IE问题
2018/09/03 Javascript
在mpvue框架中使用Vant WeappUI组件库的注意事项【推进】
2019/06/09 Javascript
js canvas实现5张图片合成一张图片
2019/07/15 Javascript
vue实现百度搜索功能
2020/12/28 Javascript
mapboxgl区划标签避让不遮盖实现的代码详解
2020/07/01 Javascript
Python下的twisted框架入门指引
2015/04/15 Python
python中的闭包用法实例详解
2015/05/05 Python
Python实现的文本对比报告生成工具示例
2018/05/22 Python
python itchat给指定联系人发消息的方法
2019/06/11 Python
python GUI库图形界面开发之PyQt5线程类QThread详细使用方法
2020/02/26 Python
Python Dataframe常见索引方式详解
2020/05/27 Python
Python实现一个简单的递归下降分析器
2020/08/01 Python
幼儿园中班开学寄语
2014/04/03 职场文书
八月迷情观后感
2015/06/11 职场文书
让子弹飞观后感
2015/06/11 职场文书
领导干部学习十八届五中全会精神心得体会
2016/01/05 职场文书
浅谈MySQL 亿级数据分页的优化
2021/06/15 MySQL
http通过StreamingHttpResponse完成连续的数据传输长链接方式
2022/02/12 Python
Python pyecharts绘制条形图详解
2022/04/02 Python