理解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高亮效果的二种实现方法
Sep 14 Javascript
jquery下组织javascript代码(js函数化)
Aug 25 Javascript
JavaScript实现网页图片等比例缩放实现代码及调用方式
Feb 25 Javascript
node.js中的http.request.end方法使用说明
Dec 10 Javascript
node.js中的http.createServer方法使用说明
Dec 14 Javascript
javascript限制文本框输入值类型的方法
May 07 Javascript
JS中Location使用详解
May 12 Javascript
AngularJS入门教程之静态模板详解
Aug 18 Javascript
Node.js开发教程之基于OnceIO框架实现文件上传和验证功能
Nov 30 Javascript
npm国内镜像 安装失败的几种解决方案
Jun 04 Javascript
vue+element_ui上传文件,并传递额外参数操作
Dec 05 Vue.js
JS 基本概念详细介绍
Oct 16 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基于Snoopy解析网页html的方法
2015/07/09 PHP
php类自动加载器实现方法
2015/07/28 PHP
PHP遍历目录文件的常用方法小结
2017/02/03 PHP
php str_getcsv把字符串解析为数组的实现方法
2017/04/05 PHP
PHP-FPM 的管理和配置详解
2019/02/17 PHP
关于PHP求解三数之和问题详析
2020/11/09 PHP
JavaScript面向对象之体会[总结]
2008/11/13 Javascript
jquery 简单导航实现代码
2009/09/11 Javascript
Js日期选择自动填充到输入框(界面漂亮兼容火狐)
2013/08/02 Javascript
深入分析escape()、encodeURI()、encodeURIComponent()的区别及示例
2014/08/04 Javascript
每天一篇javascript学习小结(Boolean对象)
2015/11/12 Javascript
jquery ajax局部加载方法详解(实现代码)
2016/05/12 Javascript
超简单的Vue.js环境搭建教程
2017/03/17 Javascript
Angular js 实现添加用户、修改密码、敏感字、下拉菜单的综合操作方法
2017/10/24 Javascript
nodejs分离html文件里面的js和css的方法
2019/04/09 NodeJs
vue自定义指令之面板拖拽的实现
2019/04/14 Javascript
jqGrid表格底部汇总、合计行footerrow处理
2019/08/21 Javascript
vue如何使用async、await实现同步请求
2019/12/09 Javascript
JS将指定的某个字符全部转换为其他字符实例代码
2020/10/13 Javascript
python删除过期log文件操作实例解析
2018/01/31 Python
Python continue语句实例用法
2020/02/06 Python
python 星号(*)的多种用途
2020/09/21 Python
如何在scrapy中捕获并处理各种异常
2020/09/28 Python
两种CSS3伪类选择器详细介绍
2013/12/24 HTML / CSS
animation和transition的区别
2020/10/12 HTML / CSS
伦敦哈德森鞋:Hudson Shoes
2018/02/06 全球购物
英国优质家居用品网上品牌:URBANARA
2018/06/01 全球购物
英国马匹装备和马术用品购物网站:Equine Superstore
2019/03/03 全球购物
What is EJB
2016/07/22 面试题
5个HTML5的常用本地存储方式详解与介绍
2021/03/27 HTML / CSS
优秀干部获奖感言
2014/01/31 职场文书
业务内勤岗位职责
2014/04/30 职场文书
我的梦想演讲稿1000字
2014/08/21 职场文书
2014年企业员工工作总结
2014/12/09 职场文书
2016幼儿园教师节新闻稿
2015/11/25 职场文书
Go语言基础map用法及示例详解
2021/11/17 Golang