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中使用构造器创建对象无需new的情况说明
Mar 01 Javascript
JavaScript分秒倒计时器实现方法
Feb 02 Javascript
jQuery layui常用方法介绍
Jul 25 Javascript
又一枚精彩的弹幕效果jQuery实现
Jul 25 Javascript
js 调用百度分享功能
Feb 27 Javascript
详解vuejs之v-for列表渲染
Jun 22 Javascript
微信js-sdk 录音功能的示例代码
Nov 01 Javascript
解决vue admin element noCache设置无效的问题
Nov 12 Javascript
vue 使用async写数字动态加载效果案例
Jul 18 Javascript
解决Vue router-link绑定事件不生效的问题
Jul 22 Javascript
封装 axios+promise通用请求函数操作
Aug 11 Javascript
Node.JS如何实现JWT原理
Sep 18 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
阿拉伯的咖啡与水烟
2021/03/03 咖啡文化
在PHP中使用curl_init函数的说明
2010/11/02 PHP
深入掌握include_once与require_once的区别
2013/06/17 PHP
ThinkPHP3.1数据CURD操作快速入门
2014/06/19 PHP
php中file_get_content 和curl以及fopen 效率分析
2014/09/19 PHP
PHP实现下载远程图片保存到本地的方法
2017/06/19 PHP
常用简易JavaScript函数
2009/04/09 Javascript
JavaScript 面向对象编程(1) 基础
2010/05/18 Javascript
window.location.hash 使用说明
2010/11/08 Javascript
基于jQuery实现图片的前进与后退功能
2013/04/24 Javascript
JQuery中$.each 和$(selector).each()的区别详解
2015/03/13 Javascript
超级给力的JavaScript的React框架入门教程
2015/07/02 Javascript
利用jQuery实现WordPress中@的ID悬浮显示评论内容
2015/12/11 Javascript
js+flash实现的5图变换效果广告代码(附演示与demo源码下载)
2016/04/01 Javascript
微信小程序中post方法与get方法的封装
2017/09/26 Javascript
vue实现图片滚动的示例代码(类似走马灯效果)
2018/03/03 Javascript
浅谈Webpack 持久化缓存实践
2018/03/22 Javascript
vue使用localStorage保存登录信息 适用于移动端、PC端
2019/05/27 Javascript
Vue+Element实现表格编辑、删除、以及新增行的最优方法
2019/05/28 Javascript
JS中如何轻松遍历对象属性的方式总结
2019/08/06 Javascript
Openlayers绘制聚合标注
2020/09/28 Javascript
rhythmbox中文名乱码问题解决方法
2008/09/06 Python
Python编写电话薄实现增删改查功能
2016/05/07 Python
pandas对指定列进行填充的方法
2018/04/11 Python
python3 selenium 切换窗口的几种方法小结
2018/05/21 Python
Python subprocess模块功能与常见用法实例详解
2018/06/28 Python
用Python实现读写锁的示例代码
2018/11/05 Python
python 并发编程 多路复用IO模型详解
2019/08/20 Python
Python Pandas 对列/行进行选择,增加,删除操作
2020/05/17 Python
十佳青年个人事迹材料
2014/01/28 职场文书
大学学习计划书范文
2014/05/02 职场文书
学校百日安全活动总结
2015/05/07 职场文书
2015年电教工作总结
2015/05/26 职场文书
小学一年级语文教学反思
2016/03/03 职场文书
如何在CSS中绘制曲线图形及展示动画
2021/05/24 HTML / CSS
Three.js实现雪糕地球的使用示例详解
2022/07/07 Javascript