理解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 相关文章推荐
自用js开发框架小成 学习js的朋友可以看看
Nov 16 Javascript
更优雅的事件触发兼容
Oct 24 Javascript
js open() 与showModalDialog()方法使用介绍
Sep 10 Javascript
浅谈使用MVC模式进行JavaScript程序开发
Nov 10 Javascript
javascript针对不确定函数的执行方法
Dec 16 Javascript
JCrop+ajaxUpload 图像切割上传的实例代码
Jul 20 Javascript
前端设计师们最常用的JS代码汇总
Sep 25 Javascript
vue移动端实现红包雨效果
Jun 23 Javascript
Angular5集成eventbus的示例代码
Jul 19 Javascript
bootstrap 路径导航 分页 进度条的实例代码
Aug 06 Javascript
使用异步组件优化Vue应用程序的性能
Apr 28 Javascript
vue封装自定义指令之动态显示title操作(溢出显示,不溢出不显示)
Nov 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
PHP5中使用PDO连接数据库的方法
2010/08/01 PHP
smarty巧妙处理iframe中内容页的代码
2012/03/07 PHP
Yii查询生成器(Query Builder)用法实例教程
2014/09/04 PHP
一个经典实用的PHP图像处理类分享
2014/11/18 PHP
PHP IDE PHPStorm配置支持友好Laravel代码提示方法
2015/05/12 PHP
PHP编程基本语法快速入门手册
2016/01/07 PHP
详解PHP匿名函数与注意事项
2016/03/29 PHP
JavaScript与函数式编程解释
2007/04/27 Javascript
JS实现关键字搜索时的相关下拉字段效果
2014/08/05 Javascript
node.js中的buffer.toString方法使用说明
2014/12/14 Javascript
前端实现文件的断点续传(前端文件提交+后端PHP文件接收)
2016/11/04 Javascript
Ionic2系列之使用DeepLinker实现指定页面URL
2016/11/21 Javascript
jquery 校验中国身份证号码实例详解
2017/04/11 jQuery
Vue.js列表渲染绑定jQuery插件的正确姿势
2017/06/29 jQuery
微信小程序之发送短信倒计时功能
2017/08/30 Javascript
vue.js数据绑定操作详解
2018/04/23 Javascript
利用chrome浏览器进行js调试并找出元素绑定的点击事件详解
2021/01/30 Javascript
详解ES6 系列之异步处理实战
2018/10/26 Javascript
vue通信方式EventBus的实现代码详解
2019/06/10 Javascript
vue.js 打包时出现空白页和路径错误问题及解决方法
2019/06/26 Javascript
vue之a-table中实现清空选中的数据
2019/11/07 Javascript
vuex+axios+element-ui实现页面请求loading操作示例
2020/02/02 Javascript
python里对list中的整数求平均并排序
2014/09/12 Python
如何解决django配置settings时遇到Could not import settings 'conf.local'
2014/11/18 Python
Python及PyCharm下载与安装教程
2017/11/18 Python
python使用phoenixdb操作hbase的方法示例
2019/02/28 Python
pandas如何处理缺失值
2019/07/31 Python
pycharm修改file type方式
2019/11/19 Python
全世界最美丽的四星和五星级酒店预订:Prestigia.com
2017/11/15 全球购物
京东奢侈品:全球奢侈品牌
2018/03/17 全球购物
缓刑人员的思想汇报
2014/01/11 职场文书
大学生学年自我鉴定
2014/02/10 职场文书
自我管理的活动方案
2014/08/25 职场文书
2014教育局对照检查材料思想汇报
2014/09/23 职场文书
2015年纪检监察工作总结
2015/04/08 职场文书
Python如何加载模型并查看网络
2022/07/15 Python