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 相关文章推荐
jQuery生成asp.net服务器控件的代码
Feb 04 Javascript
jQuery+.net实现浏览更多内容(改编php版本)
Mar 28 Javascript
Jquery chosen动态设置值实例介绍
Aug 08 Javascript
JavaScript中的数值范围介绍
Dec 29 Javascript
js实现获取当前时间是本月第几周的方法
Aug 11 Javascript
javascript表单处理具体实现代码(表单、链接、按钮)
May 07 Javascript
使用Angular缓存父页面数据的方法
Jan 03 Javascript
jquery实现图片放大点击切换
Jun 06 jQuery
node.js调用C++函数的方法示例
Sep 21 Javascript
微信小程序实现下拉菜单切换效果
Mar 30 Javascript
微信小程序实现上拉加载功能
Nov 20 Javascript
Vue组件更新数据v-model不生效的解决
Apr 02 Vue.js
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 字符转义 注意事项
2009/05/27 PHP
ThinkPHP框架搭建及常见问题(XAMPP安装失败、Apache/MySQL启动失败)
2016/04/15 PHP
Yii框架弹出框功能示例
2017/01/07 PHP
php实现简单加入购物车功能
2017/03/07 PHP
js 优化次数过多的循环 考虑到性能问题
2011/03/05 Javascript
js内存泄露的几种情况详细探讨
2013/05/31 Javascript
javascript 获取模态窗口的滚动位置代码
2013/08/06 Javascript
多引号嵌套的变量命名的问题
2014/05/09 Javascript
jQuery制作仿Mac Lion OS滚动条效果
2015/02/10 Javascript
浅谈JavaScript中的String对象常用方法
2015/02/25 Javascript
javascript判断并获取注册表中可信任站点的方法
2015/06/01 Javascript
JS实现黑客帝国文字下落效果
2015/09/01 Javascript
js将滚动条滚动到指定位置的简单实现方法
2016/06/25 Javascript
jQuery实现点击查看大图并以弹框的形式居中
2016/08/08 Javascript
除Console.log()外更多的Javascript调试命令
2018/01/24 Javascript
Koa项目搭建过程详细记录
2018/04/12 Javascript
浅谈VUE中演示v-for为什么要加key
2020/01/16 Javascript
[02:34]DOTA2英雄基础教程 幽鬼
2014/01/02 DOTA
尝试使用Python多线程抓取代理服务器IP地址的示例
2015/11/09 Python
Python微信库:itchat的用法详解
2017/08/14 Python
对numpy中数组元素的统一赋值实例
2018/04/04 Python
对DJango视图(views)和模版(templates)的使用详解
2019/07/17 Python
python实现高斯投影正反算方式
2020/01/17 Python
tensorflow tf.train.batch之数据批量读取方式
2020/01/20 Python
python中 _、__、__xx__()区别及使用场景
2020/06/30 Python
python 解决pycharm运行py文件只有unittest选项的问题
2020/09/01 Python
Html5 APP中监听返回事件处理的方法示例
2018/03/15 HTML / CSS
母亲节演讲稿范文
2014/01/02 职场文书
大学新生军训感言
2014/02/25 职场文书
2015国际残疾人日活动总结
2015/03/24 职场文书
2015年教师工作总结范文
2015/03/31 职场文书
2015年公务员转正工作总结
2015/04/24 职场文书
入党积极分子党小组意见
2015/06/02 职场文书
公司车队管理制度
2015/08/04 职场文书
Oracle以逗号分隔的字符串拆分为多行数据实例详解
2021/07/16 Oracle
大型强子对撞机再次重启探索“第五种自然力”
2022/04/29 数码科技