理解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 相关文章推荐
Locate a File Using a File Open Dialog Box
Jun 18 Javascript
getElementByIdx_x js自定义getElementById函数
Jan 24 Javascript
LABjs、RequireJS、SeaJS的区别
Mar 04 Javascript
使用jquery实现以post打开新窗口
Mar 19 Javascript
标题过长使用javascript按字节截取字符串
Apr 24 Javascript
javascript相关事件的几个概念
May 21 Javascript
jQuery实现为控件添加水印文字效果(附源码)
Dec 02 Javascript
详解原生js实现offset方法
Jun 15 Javascript
详解Vue 全局引入bass.scss 处理方案
Mar 26 Javascript
vue地区选择组件教程详解
May 04 Javascript
Vue源码探究之状态初始化
Nov 14 Javascript
小程序云开发教程如何使用云函数实现点赞功能
May 18 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代码中class样式属性的方法
2017/05/24 PHP
laravel框架路由分组,中间件,命名空间,子域名,路由前缀实例分析
2020/02/18 PHP
php实现图片压缩处理
2020/09/09 PHP
使用按钮控制以何种方式打开新窗口的属性介绍
2012/12/17 Javascript
Js表格万条数据瞬间加载实现代码
2014/02/20 Javascript
JS实现获取键盘按下的按键并显示在页面上的方法
2015/11/04 Javascript
bootstrap Table插件使用demo
2017/08/07 Javascript
基于substring()和substr()的使用以及区别(实例讲解)
2017/12/28 Javascript
jquery 时间戳转日期过程详解
2019/10/12 jQuery
vue数据更新UI不刷新显示的解决办法
2020/08/06 Javascript
jQuery中getJSON跨域原理的深入讲解
2020/09/02 jQuery
Vue+scss白天和夜间模式切换功能的实现方法
2021/01/05 Vue.js
Python通过websocket与js客户端通信示例分析
2014/06/25 Python
对于Python异常处理慎用“except:pass”建议
2015/04/02 Python
在Python中使用dict和set方法的教程
2015/04/27 Python
Python实现基于权重的随机数2种方法
2015/04/28 Python
python和bash统计CPU利用率的方法
2015/07/10 Python
Djang中静态文件配置方法
2015/07/30 Python
详解python中的文件与目录操作
2017/07/11 Python
Python异常对代码运行性能的影响实例解析
2018/02/08 Python
python 获取list特定元素下标的实例讲解
2018/04/09 Python
python使用opencv在Windows下调用摄像头实现解析
2019/11/26 Python
对django 2.x版本中models.ForeignKey()外键说明介绍
2020/03/30 Python
Python 解析xml文件的示例
2020/09/29 Python
css3媒体查询中device-width和width的区别详解
2020/03/27 HTML / CSS
Joules美国官网:出色的英国风格
2017/10/30 全球购物
巴西葡萄酒销售网站:Wine.com.br
2017/11/07 全球购物
Vichy薇姿加拿大官网:法国药妆,全球专业敏感肌护肤领先品牌
2018/07/11 全球购物
领导干部考察材料
2014/02/08 职场文书
《千年梦圆在今朝》教学反思
2014/02/24 职场文书
关爱留守儿童标语
2014/06/18 职场文书
电子商务优秀毕业生求职信
2014/07/11 职场文书
中秋节国旗下演讲稿
2014/09/13 职场文书
文案策划岗位职责
2015/02/11 职场文书
淮海战役观后感
2015/06/11 职场文书
Vue组件更新数据v-model不生效的解决
2022/04/02 Vue.js