JavaScript利用闭包实现模块化

发布时间 - 2026-01-10 22:31:22    点击率:

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

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 对象的内部引用,可以从内部对模块实例进行修改,包括添加或删除方法和属性,以及修改它们的值。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


# js  # 闭包  # 模块化  # JS沙箱模式实例分析  # JavaScript 设计模式 安全沙箱模式  # JavaScript的模块化:封装(闭包)  # 继承(原型) 介绍  # JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)  # js面向对象之常见创建对象的几种方式(工厂模式、构造函数模式、原型模式)  # JavaScript设计模式之观察者模式(发布者-订阅者模式)  # JavaScript 设计模式之组合模式解析  # javascript 设计模式之单体模式 面向对象学习基础  # javascript设计模式之解释器模式详解  # 常用的Javascript设计模式小结  # JavaScript设计模式之工厂方法模式介绍  # JS实现闭包中的沙箱模式示例  # 创建一个  # 返回值  # 被称为  # 它来  # 的是  # 都是  # 很好  # 域外  # 中有  # 这段  # 能在  # 可以通过  # 并将  # 可以直接  # 上看  # 必要条件  # 或删除  # 只需要  # 而这  # 来实现 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: JavaScript如何实现路由_前端路由原理是什么  Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】  Swift中swift中的switch 语句  JavaScript实现Fly Bird小游戏  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  如何在宝塔面板中修改默认建站目录?  Laravel如何实现用户注册和登录?(Auth脚手架指南)  千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】  油猴 教程,油猴搜脚本为什么会网页无法显示?  零服务器AI建站解决方案:快速部署与云端平台低成本实践  简历没回改:利用AI润色让你的文字更专业  Laravel如何编写单元测试和功能测试?(PHPUnit示例)  北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  Laravel如何发送邮件和通知_Laravel邮件与通知系统发送步骤  儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?  如何在阿里云完成域名注册与建站?  怎么用AI帮你设计一套个性化的手机App图标?  如何在阿里云虚拟服务器快速搭建网站?  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程  如何在万网利用已有域名快速建站?  Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】  Python企业级消息系统教程_KafkaRabbitMQ高并发应用  专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?  Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】  如何将凡科建站内容保存为本地文件?  HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】  Laravel如何处理文件下载请求?(Response示例)  Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】  如何用wdcp快速搭建高效网站?  网站页面设计需要考虑到这些问题  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  制作公司内部网站有哪些,内网如何建网站?  1688铺货到淘宝怎么操作 1688一键铺货到自己店铺详细步骤  如何快速搭建高效香港服务器网站?  Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用  JS去除重复并统计数量的实现方法  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  Laravel模型关联查询教程_Laravel Eloquent一对多关联写法  Mybatis 中的insertOrUpdate操作  如何在阿里云ECS服务器部署织梦CMS网站?  Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】  北京网站制作公司哪家好一点,北京租房网站有哪些?  使用PHP下载CSS文件中的所有图片【几行代码即可实现】  Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】  高防服务器租用如何选择配置与防御等级?  Laravel如何与Docker(Sail)协同开发?(环境搭建教程)  b2c电商网站制作流程,b2c水平综合的电商平台?  Internet Explorer官网直接进入 IE浏览器在线体验版网址  浅析上传头像示例及其注意事项