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重新播放css动画所遇问题解决
Aug 21 Javascript
12种不宜使用的Javascript语法整理
Nov 04 Javascript
JS获取计算机mac地址以及IP的实现方法
Jan 08 Javascript
jQuery中阻止冒泡事件的方法介绍
Apr 12 Javascript
浅析javascript中的DOM
Mar 01 Javascript
jQuery使用drag效果实现自由拖拽div
Jun 11 Javascript
Bootstrap中CSS的使用方法
Feb 17 Javascript
使用Javascript实现选择下拉菜单互移并排序
Feb 23 Javascript
AngularJS基础 ng-repeat 指令简单示例
Aug 03 Javascript
浅谈jQuery before和insertBefore的区别
Dec 04 Javascript
jQuery焦点图左右转换效果
Dec 12 Javascript
解决Vue打包上线之后部分CSS不生效的问题
Nov 12 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字符串函数的总结分析
2013/06/05 PHP
ThinkPHP和UCenter接口冲突的解决方法
2016/07/25 PHP
jquery 指南/入门基础
2007/11/30 Javascript
javascript实现的弹出层背景置灰-模拟(easyui dialog)
2013/12/27 Javascript
js中unicode转码方法详解
2015/10/09 Javascript
详解JS面向对象编程
2016/01/24 Javascript
jQuery日历插件datepicker用法详解
2016/03/03 Javascript
Avalon中文长字符截取、关键字符隐藏、自定义过滤器
2016/05/18 Javascript
javascript数组遍历的方法实例分析
2016/09/13 Javascript
详解Vue2 无限级分类(添加,删除,修改)
2017/03/07 Javascript
jQuery导航条固定定位效果实例代码
2017/05/26 jQuery
无限循环轮播图之运动框架(原生JS实现)
2017/10/01 Javascript
bootstrap3中container与container_fluid外层容器的区别讲解
2017/12/04 Javascript
使用 vue 实例更好的监听事件及vue实例的方法
2019/04/22 Javascript
基于小程序请求接口wx.request封装的类axios请求
2020/07/02 Javascript
浅谈vue中get请求解决传输数据是数组格式的问题
2020/08/03 Javascript
Python多线程编程(三):threading.Thread类的重要函数和方法
2015/04/05 Python
python 实现上传图片并预览的3种方法(推荐)
2017/07/14 Python
利用python模拟实现POST请求提交图片的方法
2017/07/25 Python
Python实现图片滑动式验证识别方法
2017/11/09 Python
python使用sqlite3时游标使用方法
2018/03/13 Python
Numpy中矩阵matrix读取一列的方法及数组和矩阵的相互转换实例
2018/07/02 Python
关于windows下Tensorflow和pytorch安装教程
2020/02/04 Python
python 发送get请求接口详解
2020/11/17 Python
英国山地公路自行车商店:Tweeks Cycles
2018/03/16 全球购物
zooplus波兰:在线宠物店
2019/07/21 全球购物
给上级领导的感谢信
2015/01/22 职场文书
水电施工员岗位职责
2015/04/11 职场文书
2015年幼儿园中班下学期工作总结
2015/05/22 职场文书
消防宣传语大全
2015/07/13 职场文书
《为人民服务》教学反思
2016/02/20 职场文书
nginx请求限制配置方法
2021/07/09 Servers
Redis如何使用乐观锁(CAS)保证数据一致性
2022/03/25 Redis
Java 获取Word中所有的插入和删除修订的方法
2022/04/06 Java/Android
python中pycryto实现数据加密
2022/04/29 Python
基于redis+lua进行限流的方法
2022/07/23 Redis