JavaScript利用闭包实现模块化


Posted in Javascript onJanuary 13, 2017

利用闭包的强大威力,但从表面上看,它们似乎与回调无关。下面一起来研究其中最强大的一个:模块。

function foo() {
 var something = "cool";
 var another = [1, 2, 3];
 function doSomething() {
 console.log( something );
 }
 function doAnother() {
 console.log( another.join( " ! " ) );
 }
}

正如在这段代码中所看到的,这里并没有明显的闭包,只有两个私有数据变量something和another,以及doSomething() 和doAnother() 两个内部函数,它们的词法作用域(而这就是闭包)也就是foo() 的内部作用域。

接下来考虑以下代码:

function CoolModule() {
 var something = "cool";
 var another = [1, 2, 3];
 function doSomething() {
 alert( something );
 }
 function doAnother() {
 alert( another.join( " ! " ) );
 }
 return {
 doSomething: doSomething,
 doAnother: doAnother
 };
}
var foo = CoolModule();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3

这个模式在JavaScript 中被称为模块。最常见的实现模块模式的方法通常被称为模块暴露,这里展示的是其变体。我们仔细研究一下这些代码。

首先,CoolModule() 只是一个函数,必须要通过调用它来创建一个模块实例。如果不执行外部函数,内部作用域和闭包都无法被创建。其次,CoolModule() 返回一个用对象字面量语法{ key: value, ... } 来表示的对象。这个返回的对象中含有对内部函数而不是内部数据变量的引用。我们保持内部数据变量是隐藏且私有的状态。可以将这个对象类型的返回值看作本质上是模块的公共API。这个对象类型的返回值最终被赋值给外部的变量foo,然后就可以通过它来访问API 中的属性方法,比如foo.doSomething()。

从模块中返回一个实际的对象并不是必须的,也可以直接返回一个内部函数。jQuery 就是一个很好的例子。jQuery 和$ 标识符就是jQuery 模块的公共API,但它们本身都是函数(由于函数也是对象,它们本身也可以拥有属性)。

doSomething() 和doAnother() 函数具有涵盖模块实例内部作用域的闭包( 通过调用CoolModule() 实现)。当通过返回一个含有属性引用的对象的方式来将函数传递到词法作用域外部时,我们已经创造了可以观察和实践闭包的条件。如果要更简单的描述,模块模式需要具备两个必要条件。

1. 必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)。

2. 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态。

一个具有函数属性的对象本身并不是真正的模块。从方便观察的角度看,一个从函数调用所返回的,只有数据属性而没有闭包函数的对象并不是真正的模块。上一个示例代码中有一个叫作CoolModule() 的独立的模块创建器,可以被调用任意多次,每次调用都会创建一个新的模块实例。当只需要一个实例时,可以对这个模式进行简单的改进来实现单例模式:

var foo = (function CoolModule() {
 var something = "cool";
 var another = [1, 2, 3];
 function doSomething() {
 alert( something );
 }
 function doAnother() {
 alert( another.join( " ! " ) );
 }
 return {
 doSomething: doSomething,
 doAnother: doAnother
 };
})();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3

立即调用这个函数并将返回值直接赋值给单例的模块实例标识符foo。

模块也是普通的函数,因此可以接受参数:

function CoolModule(id) {
 function identify() {
 console.log( id );
 }
 return {
 identify: identify
 };
}
var foo1 = CoolModule( "foo 1" );
var foo2 = CoolModule( "foo 2" );
foo1.identify(); // "foo 1"
foo2.identify(); // "foo 2"

模块模式另一个简单但强大的变化用法是,命名将要作为公共API 返回的对象:

var foo = (function CoolModule(id) {
function change() {
 // 修改公共API
 publicAPI.identify = identify2;
}
function identify1() {
 alert( id );
}
function identify2() {
 alert( id.toUpperCase() );
}
var publicAPI = {
 change: change,
 identify: identify1
};
return publicAPI;
})( "foo module" );
foo.identify(); // foo module
foo.change();
foo.identify(); // FOO MODULE

通过在模块实例的内部保留对公共API 对象的内部引用,可以从内部对模块实例进行修改,包括添加或删除方法和属性,以及修改它们的值。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
解决使用attachEvent函数时,this指向被绑定的元素的问题的方法
Aug 13 Javascript
javascript innerHTML、outerHTML、innerText、outerText的区别
Nov 24 Javascript
js 实现无缝滚动 兼容IE和FF
Jul 15 Javascript
通过百度地图获取公交线路的站点坐标的js代码
May 11 Javascript
利用js实现选项卡的特别效果的实例
Mar 03 Javascript
javascript截取字符串(通过substring实现并支持中英文混合)
Jun 24 Javascript
vue v-for循环重复数据无法添加问题解决方法【加track-by='索引'】
Mar 15 Javascript
微信小程序数据统计和错误统计的实现方法
Jun 26 Javascript
js HTML DOM EventListener功能与用法实例分析
Apr 27 Javascript
JavaScript Array.flat()函数用法解析
Sep 02 Javascript
Vue实现简单的留言板
Oct 23 Javascript
解决vscode进行vue格式化,会自动补分号和双引号的问题
Oct 26 Javascript
Vue.js基础知识小结
Jan 13 #Javascript
canvas实现流星雨的背景效果
Jan 13 #Javascript
JavaScript正则表达式替换字符串中图片地址(img src)的方法
Jan 13 #Javascript
原生js实现手风琴功能(支持横纵向调用)
Jan 13 #Javascript
JavaScript使用简单正则表达式的数据验证功能示例
Jan 13 #Javascript
bootstrap网格系统使用方法解析
Jan 13 #Javascript
js 判断数据类型的几种方法
Jan 13 #Javascript
You might like
php中目录,文件操作详谈
2007/03/19 PHP
采用memcache在web集群中实现session的同步会话
2014/07/05 PHP
MacOS 安装 PHP的图片裁剪扩展Tclip
2015/03/25 PHP
javascript下IE与FF兼容函数收集
2008/09/17 Javascript
jquery遍历数组与筛选数组的方法
2013/11/05 Javascript
JS动态修改图片的URL(src)的方法
2015/04/01 Javascript
javascript操作ul中li的方法
2015/05/14 Javascript
JS实现点击按钮获取页面高度的方法
2015/11/02 Javascript
jquery捕捉回车键及获取checkbox值与异步请求的方法
2015/12/24 Javascript
JS正则表达式验证密码格式的集中情况总结
2017/02/23 Javascript
vue.js或js实现中文A-Z排序的方法
2018/03/08 Javascript
vue中的数据绑定原理的实现
2018/07/02 Javascript
[02:26]2016国际邀请赛8月3日开战 中国军团出征西雅图
2016/08/02 DOTA
python模拟登录百度代码分享(获取百度贴吧等级)
2013/12/27 Python
Python多线程同步Lock、RLock、Semaphore、Event实例
2014/11/21 Python
浅析Python中的序列化存储的方法
2015/04/28 Python
ubuntu环境下python虚拟环境的安装过程
2018/01/07 Python
详解python项目实战:模拟登陆CSDN
2019/04/04 Python
基于Tensorflow:CPU性能分析
2020/02/10 Python
pandas中的数据去重处理的实现方法
2020/02/10 Python
python GUI框架pyqt5 对图片进行流式布局的方法(瀑布流flowlayout)
2020/03/12 Python
python如何从键盘获取输入实例
2020/06/18 Python
Python 实现进度条的六种方式
2021/01/06 Python
StubHub西班牙:购买和出售全球活动门票
2017/06/05 全球购物
意大利灯具购物网站:Lampade.it
2018/10/18 全球购物
法学专业本科生自荐信范文
2013/12/17 职场文书
工作睡觉检讨书
2014/02/25 职场文书
大课间活动实施方案
2014/03/06 职场文书
专业技术职务聘任书
2014/03/29 职场文书
财务人员担保书
2014/05/13 职场文书
冬季施工防火方案
2014/05/17 职场文书
个人租房协议书
2014/11/28 职场文书
2015年财务试用期工作总结
2014/12/24 职场文书
社区党支部承诺书
2015/04/29 职场文书
《吃水不忘挖井人》教学反思
2016/02/22 职场文书
Javascript设计模式之原型模式详细
2021/10/05 Javascript