打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
JavaScript利用闭包实现模块化

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

 1 function foo() { 2     var something = "cool"; 3     var another = [1, 2, 3]; 4     function doSomething() { 5         console.log( something ); 6     } 7     function doAnother() { 8         console.log( another.join( " ! " ) ); 9     }10 }

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

 1 function CoolModule() { 2     var something = "cool"; 3     var another = [1, 2, 3]; 4  5     function doSomething() { 6         alert( something ); 7     } 8     function doAnother() { 9         alert( another.join( " ! " ) );10     }11     return {12         doSomething: doSomething,13         doAnother: doAnother14     };15 }16 var foo = CoolModule();17 foo.doSomething(); // cool18 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() 的独立的模块创建器,可以被调用任意多次,每次调用都会创建一个新的模块实例。当只需要一个实例时,可以对这个模式进行简单的改进来实现单例模式:

 1 var foo = (function CoolModule() { 2     var something = "cool"; 3     var another = [1, 2, 3]; 4  5     function doSomething() { 6         alert( something ); 7     } 8     function doAnother() { 9         alert( another.join( " ! " ) );10     }11     return {12         doSomething: doSomething,13         doAnother: doAnother14     };15 })();16 foo.doSomething(); // cool17 foo.doAnother(); // 1 ! 2 ! 3

立即调用这个函数并将返回值直接赋值给单例的模块实例标识符foo。
模块也是普通的函数,因此可以接受参数:

 1 function CoolModule(id) { 2     function identify() { 3         console.log( id ); 4     } 5     return { 6         identify: identify 7     }; 8 } 9 var foo1 = CoolModule( "foo 1" );10 var foo2 = CoolModule( "foo 2" );11 foo1.identify(); // "foo 1"12 foo2.identify(); // "foo 2"

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

 1 var foo = (function CoolModule(id) { 2 function change() { 3     // 修改公共API 4     publicAPI.identify = identify2; 5 } 6 function identify1() { 7     alert( id ); 8 } 9 function identify2() {10     alert( id.toUpperCase() );11 }12 var publicAPI = {13     change: change,14     identify: identify115 };16 return publicAPI;17 })( "foo module" );18 foo.identify(); // foo module19 foo.change();20 foo.identify(); // FOO MODULE

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

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
说一说JS的IIFE
JavaScript 函数
Unity3D内部脚本编程入门
Unity3D教程:脚本初级知识(二) | Unity3D教程手册
js中回调函数的学习笔记
你可能不知道的10个JavaScript小技巧 - 梦想天空 - 博客园
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服