理解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实现一个页面多个css样式实现
May 29 Javascript
JavaScript动态添加列的方法
Mar 25 Javascript
纯JS实现本地图片预览的方法
Jul 31 Javascript
微信小程序 用户数据解密详细介绍
Jan 09 Javascript
JS实现的四级密码强度检测功能示例
May 11 Javascript
node中IO以及定时器优先级详解
May 10 Javascript
vue+element-ui+axios实现图片上传
Aug 20 Javascript
使用layer.msg 时间设置不起作用的解决方法
Sep 12 Javascript
解决layui轮播图有数据不显示的情况
Sep 16 Javascript
微信小程序整个页面的自动适应布局的实现
Jul 12 Javascript
JS继承实现方法及优缺点详解
Sep 02 Javascript
基于Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能
Jan 05 Vue.js
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
thinkphp5实现无限级分类
2019/02/18 PHP
图片自动更新(说明)
2006/10/02 Javascript
JavaScript学习历程和心得小结
2010/08/16 Javascript
jQuery队列控制方法详解queue()/dequeue()/clearQueue()
2010/12/02 Javascript
js综合应用实例简单的表格统计
2013/09/03 Javascript
JQuery实现动态表格点击按钮表格增加一行
2014/08/24 Javascript
超级好用的jQuery圆角插件 Corner速成
2014/08/31 Javascript
sails框架的学习指南
2014/12/22 Javascript
JS中多步骤多分步的StepJump组件实例详解
2016/04/01 Javascript
js 弹出虚拟键盘修改密码的简单实例
2016/10/10 Javascript
JS基于面向对象实现的多个倒计时器功能示例
2017/02/28 Javascript
jquery仿ps颜色拾取功能
2017/03/08 Javascript
微信小程序支付之c#后台实现方法
2017/10/19 Javascript
vue 右键菜单插件 简单、可扩展、样式自定义的右键菜单
2018/11/29 Javascript
JS监听滚动和id自动定位滚动
2018/12/18 Javascript
vue filter 完美时间日期格式的代码
2019/08/14 Javascript
[51:15]2014 DOTA2国际邀请赛中国区预选赛 Orenda VS LGD-GAMING
2014/05/22 DOTA
python Django批量导入数据
2016/03/25 Python
Python数据分析之如何利用pandas查询数据示例代码
2017/09/01 Python
Python实现Logger打印功能的方法详解
2017/09/01 Python
浅谈Pandas 排序之后索引的问题
2018/06/07 Python
详解python中docx库的安装过程
2019/11/08 Python
解决Keras的自定义lambda层去reshape张量时model保存出错问题
2020/07/01 Python
有关pycharm登录github时有的时候会报错connection reset的问题
2020/09/15 Python
Python爬虫UA伪装爬取的实例讲解
2021/02/19 Python
个人简历自荐信
2013/12/05 职场文书
大学生毕业的自我评价分享
2014/01/02 职场文书
教育技术职业规划范文
2014/03/04 职场文书
师德演讲稿范文
2014/05/06 职场文书
大型公益活动策划方案
2014/08/20 职场文书
2015年元旦文艺晚会总结(学院)
2014/11/28 职场文书
2015新年寄语(一句话)
2014/12/08 职场文书
python实现Thrift服务端的方法
2021/04/20 Python
Java使用httpRequest+Jsoup爬取红蓝球号码
2021/07/02 Java/Android
图片批量处理 - 尺寸、格式、水印等
2022/03/07 杂记
利用Python实时获取steam特惠游戏数据
2022/06/25 Python