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 相关文章推荐
Javascript 实用小技巧
Apr 07 Javascript
asp.net 30分钟掌握无刷新 Repeater
Sep 16 Javascript
简单的前端js+ajax 购物车框架(入门篇)
Oct 29 Javascript
jquery 设置style:display的方法
Jan 29 Javascript
JS实现弹性漂浮效果的广告代码
Sep 02 Javascript
使用JavaScript脚本判断页面是否在微信中被打开
Mar 06 Javascript
jQuery基本过滤选择器用法示例
Sep 09 Javascript
Vue侧滑菜单组件——DrawerLayout
Dec 18 Javascript
加快Vue项目的开发速度的方法
Dec 12 Javascript
8个有意思的JavaScript面试题
Jul 30 Javascript
layui 数据表格+分页+搜索+checkbox+缓存选中项数据的方法
Sep 21 Javascript
JS实现排行榜文字向上滚动轮播效果
Nov 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
Linux Apache PHP Oracle 安装配置(具体操作步骤)
2013/06/17 PHP
php实现cc攻击防御和防止快速刷新页面示例
2014/02/13 PHP
ThinkPHP中自定义目录结构的设置方法
2014/08/15 PHP
php file_get_contents取文件中数组元素的方法
2017/04/01 PHP
php在windows环境下获得cpu内存实时使用率(推荐)
2018/02/08 PHP
jQuery选择没有colspan属性的td的代码
2010/07/06 Javascript
给Flash加一个超链接(推荐使用透明层)兼容主流浏览器
2013/06/09 Javascript
判断是否存在子节点的实现代码
2016/05/18 Javascript
Bootstrap轮播插件中图片变形的终极解决方案 使用jqthumb.js
2016/07/10 Javascript
js点击按钮实现水波纹效果代码(CSS3和Canves)
2016/09/15 Javascript
web前端开发upload上传头像js示例代码
2016/10/22 Javascript
基于jQuery实现选项卡效果
2017/01/04 Javascript
select下拉框插件jquery.editable-select详解
2017/01/22 Javascript
JS+HTML5实现图片在线预览功能
2017/07/22 Javascript
关于vue.js组件数据流的问题
2017/07/26 Javascript
关于axios如何全局注册浅析
2018/01/14 Javascript
angular实现页面打印局部功能的思考与方法
2018/04/13 Javascript
一个简单的node.js界面实现方法
2018/06/01 Javascript
用vue快速开发app的脚手架工具
2018/06/11 Javascript
基于Three.js实现360度全景图片
2018/12/30 Javascript
微信小程序视图控件与bindtap之间的问题的解决
2019/04/08 Javascript
Angular中使用ng-zorro图标库部分图标不能正常显示问题
2019/04/22 Javascript
[05:01]3.19DOTA2发布会 我们都是刀塔人
2014/03/25 DOTA
Python新手实现2048小游戏
2015/03/31 Python
Django 前后台的数据传递的方法
2017/08/08 Python
Python3几个常见问题的处理方法
2019/02/26 Python
网络工程师个人的自我评价范文
2013/10/01 职场文书
机电一体化专业推荐信
2013/12/03 职场文书
考生诚信考试承诺书
2014/05/23 职场文书
人大代表选举标语
2014/10/07 职场文书
幼儿园感恩节活动方案2014
2014/10/11 职场文书
2014年检验科工作总结
2014/11/22 职场文书
2014年社区宣传工作总结
2014/12/02 职场文书
党员转正党支部意见
2015/06/02 职场文书
担保书怎么写 ?
2019/04/22 职场文书
Python采集爬取京东商品信息和评论并存入MySQL
2022/04/12 Python