理解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 字符串操作函数
Jul 25 Javascript
javascript语言结构小记(一)
Sep 10 Javascript
js数组的基本用法及数组根据下标(数值或字符)移除元素
Oct 20 Javascript
JS冒泡事件的快速解决方法
Dec 16 Javascript
JavaScript中的迭代器和生成器详解
Oct 29 Javascript
学习JavaScript设计模式(封装)
Nov 26 Javascript
node.js入门实例helloworld详解
Dec 23 Javascript
微信小程序 wx:for的使用实例详解
Apr 27 Javascript
详解如何在React组件“外”使用父组件的Props
Jan 12 Javascript
vue axios数据请求get、post方法及实例详解
Sep 11 Javascript
详解Vue2.0组件的继承与扩展
Nov 23 Javascript
jQuery动态操作表单示例【基于table表格】
Dec 06 jQuery
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同时连接多个mysql数据库示例代码
2014/03/17 PHP
浅析get与post的一些特殊情况
2014/07/28 PHP
PHP中两个float(浮点数)比较实例分析
2015/09/27 PHP
PHP使用递归算法无限遍历数组示例
2017/01/13 PHP
浅谈PHP SHA1withRSA加密生成签名及验签
2019/03/18 PHP
JQuery 常用方法基础教程
2009/02/06 Javascript
CSS+Jquery实现页面圆角框方法大全
2009/12/24 Javascript
关于UTF-8的客户端用AJAX方式获取GB2312的服务器端乱码问题的解决办法
2010/11/30 Javascript
jquery实现文字由下到上循环滚动的实例代码
2013/08/09 Javascript
javascript实现鼠标拖动改变层大小的方法
2015/04/30 Javascript
localResizeIMG先压缩后使用ajax无刷新上传(移动端)
2015/08/11 Javascript
Jquery easyui 实现动态树
2015/11/17 Javascript
全面理解JavaScript中的闭包
2016/05/12 Javascript
星期几的不同脚本写法(推荐)
2016/06/01 Javascript
基于JavaScript实现跳转提示页面
2016/09/24 Javascript
JavaScript ES6中的简写语法总结与使用技巧
2018/12/30 Javascript
Angular+Ionic使用queryParams实现跳转页传值的方法
2020/09/05 Javascript
Vue项目开发常见问题和解决方案总结
2020/09/11 Javascript
基于vue与element实现创建试卷相关功能(实例代码)
2020/12/07 Vue.js
windows下安装python paramiko模块的代码
2013/02/10 Python
Python入门篇之列表和元组
2014/10/17 Python
解决Python内层for循环如何break出外层的循环的问题
2019/06/24 Python
python set内置函数的具体使用
2019/07/02 Python
意大利文具和办公产品在线商店:Y-Office
2020/02/27 全球购物
幼儿园英语教学反思
2014/01/30 职场文书
《庐山的云雾》教学反思
2014/04/22 职场文书
典型事迹材料范文
2014/12/29 职场文书
圆明园观后感
2015/06/03 职场文书
2015年高三教学工作总结
2015/07/21 职场文书
学雷锋感言
2015/08/03 职场文书
话题作文之诚信
2019/11/28 职场文书
详解Python常用的魔法方法
2021/06/03 Python
嵌入式Redis服务器在Spring Boot测试中的使用教程
2021/07/21 Redis
html form表单基础入门案例讲解
2021/07/21 HTML / CSS
JavaScript函数柯里化
2021/11/07 Javascript
使用 Koa + TS + ESLlint 搭建node服务器的过程详解
2022/05/30 NodeJs