理解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上传图片前预览图片兼容大多数浏览器
Oct 25 Javascript
javascript获取web应用根目录的方法
Feb 12 Javascript
JavaScript如何调试有哪些建议和技巧附五款有用的调试工具
Oct 28 Javascript
分享我的jquery实现下拉菜单心的
Nov 29 Javascript
使用do...while的方法输入一个月中所有的周日(实例代码)
Jul 22 Javascript
AngularJS入门教程之Helloworld示例
Dec 25 Javascript
基于JS设计12306登录页面
Dec 28 Javascript
js实现密码强度检验
Jan 15 Javascript
JS实现移动端整屏滑动的实例代码
Nov 10 Javascript
ES6学习笔记之let与const用法实例分析
Jan 22 Javascript
nginx配置域名后的二级目录访问不同项目的配置操作
Nov 06 Javascript
vue使用require.context实现动态注册路由
Dec 25 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
Yii框架防止sql注入,xss攻击与csrf攻击的方法
2016/10/18 PHP
PHP使用Redis替代文件存储Session的方法
2017/02/15 PHP
php简单生成一组与多组随机字符串的方法
2017/05/09 PHP
PHP实现类似题库抽题效果
2018/08/16 PHP
TP5(thinkPHP框架)实现后台清除缓存功能示例
2019/05/29 PHP
PHP实现的AES 128位加密算法示例
2019/09/16 PHP
jquery 上下滚动广告
2009/06/17 Javascript
纯js实现瀑布流展现照片(自动适应窗口大小)
2013/04/08 Javascript
extjs两个tbar问题探讨
2013/08/08 Javascript
通过onmouseover选项卡实现img图片的变化
2014/02/12 Javascript
jQuery实现选中弹出窗口选择框内容后赋值给文本框的方法
2015/11/23 Javascript
JSONObject使用方法详解
2015/12/17 Javascript
Ajax验证用户名或昵称是否已被注册
2017/04/05 Javascript
jQuery自定义元素右键点击事件(实现案例)
2017/04/28 jQuery
angularjs中使用ng-bind-html和ng-include的实例
2017/04/28 Javascript
详解node中创建服务进程
2017/05/09 Javascript
Angular中的interceptors拦截器
2017/06/25 Javascript
js实现图片放大展示效果
2017/08/30 Javascript
JS实现简易换图时钟功能分析
2018/01/04 Javascript
vue子路由跳转实现tab选项卡
2019/07/24 Javascript
vue语法自动转typescript(解放双手)
2019/09/18 Javascript
Nuxt默认模板、默认布局和自定义错误页面的实现
2020/05/11 Javascript
Django项目主urls导入应用中views的红线问题解决
2019/08/10 Python
Django--权限Permissions的例子
2019/08/28 Python
PyTorch 导数应用的使用教程
2020/08/31 Python
台湾饭店和机票预订网站:Expedia台湾
2016/08/05 全球购物
世界上最大的乐谱选择:Sheet Music Plus
2020/01/18 全球购物
物理力学求职信
2014/02/18 职场文书
2014元旦晚会策划方案
2014/02/19 职场文书
活动总结的格式
2014/05/07 职场文书
行政求职信
2014/07/04 职场文书
管理人员岗位职责
2015/02/14 职场文书
小学英语教学反思范文
2016/02/15 职场文书
go mod 安装依赖 unkown revision问题的解决方案
2021/05/06 Golang
Python深度学习之实现卷积神经网络
2021/06/05 Python
Pandas自定义选项option设置
2021/07/25 Python