理解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 相关文章推荐
可拖动窗口,附带鼠标控制渐变透明,开启关闭功能
Jun 26 Javascript
jquery ajax 简单范例(界面+后台)
Nov 19 Javascript
jquery使用hide方法隐藏指定id的元素
Mar 30 Javascript
jquery SweetAlert插件实现响应式提示框
Aug 18 Javascript
js控制TR的显示隐藏
Mar 04 Javascript
canvas绘制的直线动画
Jan 23 Javascript
Bootstrap表单控件学习使用
Mar 07 Javascript
Node.js中使用mongoose操作mongodb数据库的方法
Sep 12 Javascript
Angular中使用MathJax遇到的一些问题
Dec 15 Javascript
旺旺在线客服代码 旺旺客服代码生成器
Jan 09 Javascript
Angular2中监听数据更新的方法
Aug 31 Javascript
JavaScript内置对象math,global功能与用法实例分析
Jun 10 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中动态HTML的输出技术
2006/10/09 PHP
php之字符串变相相减的代码
2007/03/19 PHP
php读取本地文件常用函数(fopen与file_get_contents)
2013/09/09 PHP
PHP的魔术常量__METHOD__简介
2014/07/08 PHP
thinkPHP5.0框架命名空间详解
2017/03/18 PHP
浅谈PHP中如何实现Hook机制
2017/11/14 PHP
javascript 禁止复制网页
2009/06/11 Javascript
JS跨域问题详解
2014/11/25 Javascript
ECMAScript6中Map/WeakMap详解
2015/06/12 Javascript
简述Matlab中size()函数的用法
2016/03/20 Javascript
利用Jquery队列实现根据输入数量显示的动画
2016/09/01 Javascript
Javascript中return的使用与闭包详解
2017/01/11 Javascript
D3.js中强制异步文件读取同步的几种方法
2017/02/06 Javascript
深究AngularJS中$sce的使用
2017/06/12 Javascript
详解Vue学习笔记入门篇之组件的内容分发(slot)
2017/07/17 Javascript
vue生命周期实例小结
2018/08/15 Javascript
vue 实现微信浮标效果
2019/09/01 Javascript
JS数组Reduce方法功能与用法实例详解
2020/04/29 Javascript
[30:37]【全国守擂赛】第三周擂主赛 Dark Knight vs. Leopard Gaming
2020/05/04 DOTA
pycharm+PyQt5+python最新开发环境配置(踩坑)
2019/02/11 Python
Python3多目标赋值及共享引用注意事项
2019/05/27 Python
python 一维二维插值实例
2020/04/22 Python
css3实现平移效果(transfrom:translate)的示例
2020/11/13 HTML / CSS
html5 worker 实例(一) 为什么测试不到效果
2013/06/24 HTML / CSS
HTML5公共页面提取作为公用代码的方法
2020/06/30 HTML / CSS
贝尔帐篷精品店:Bell Tent Boutique
2019/06/12 全球购物
澳大利亚设计师服装在线:MISHA
2019/10/07 全球购物
某公司部分笔试题
2013/11/05 面试题
幼儿园大班新学期寄语
2014/01/18 职场文书
公务员转正考察材料
2014/02/07 职场文书
银行纠风工作实施方案
2014/06/08 职场文书
管理岗位竞聘演讲稿
2014/08/18 职场文书
合伙经营协议书范本
2014/09/13 职场文书
运动会报道稿大全
2015/07/23 职场文书
2019最新版火锅店的创业计划书 !
2019/07/12 职场文书
导游词之无锡唐城
2019/12/12 职场文书