什么是模块化开发?

article/2025/10/22 9:57:33

什么是模块化开发?

前端开发中,起初只要在script标签中嵌入几十上百行代码就能实现一些基本的交互效果,后来js得到重视,应用也广泛起来了,jQuery,Ajax,Node.js,MVC,MVVM等的助力也使得前端开发得到重视,也使得前端项目越来越复杂,然而,JavaScript却没有为组织代码提供任何明显帮助,甚至没有类的概念,更不用说模块(module)了,那么什么是模块呢?

一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范,否则就都乱套了。

根据AMD规范,我们可以使用define定义模块,使用require调用模块。

目前,通行的js模块规范主要有两种:CommonJSAMD

AMD规范

AMD 即Asynchronous Module Definition,中文名是“异步模块定义”的意思。它是一个在浏览器端模块化开发的规范,服务器端的规范是CommonJS

模块将被异步加载,模块加载不影响后面语句的运行。所有依赖某些模块的语句均放置在回调函数中。

AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出。

define() 函数

AMD规范只定义了一个函数 define,它是全局变量。函数的描述为:

define(id?, dependencies?, factory);

参数说明:

id:指定义中模块的名字,可选;如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字。如果提供了该参数,模块名必须是“顶级”的和绝对的(不允许相对名字)。依赖dependencies:是一个当前模块依赖的,已被模块定义的模块标识的数组字面量。
依赖参数是可选的,如果忽略此参数,它应该默认为["require", "exports", "module"]。然而,如果工厂方法的长度属性小于3,加载器会选择以函数的长度属性指定的参数个数调用工厂方法。工厂方法factory,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。

模块名的格式

模块名用来唯一标识定义中模块,它们同样在依赖性数组中使用:

模块名是用正斜杠分割的有意义单词的字符串
单词须为驼峰形式,或者"."".."
模块名不允许文件扩展名的形式,如“.js”
模块名可以为 "相对的""顶级的"。如果首字符为“.”或“..”则为相对的模块名
顶级的模块名从根命名空间的概念模块解析
相对的模块名从 "require" 书写和调用的模块解析

使用 require 和 exports

创建一个名为"alpha"的模块,使用了requireexports,和名为"beta"的模块:

 define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {exports.verb = function() {return beta.verb();//Or:return require("beta").verb();}});

require API 介绍: https://github.com/amdjs/amdjs-api/wiki/require

AMD规范中文版:https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88)

目前,实现AMD的库有RequireJS 、curl 、Dojo 、Nodules 等。

CommonJS规范

CommonJS是服务器端模块的规范,node.js采用了这个规范。Node.JS首先采用了js模块化的概念。

根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性。

输出模块变量的最好方法是使用module.exports对象。

var i = 1;
var max = 30;module.exports = function () {for (i -= 1; i++ < max; ) {console.log(i);}max *= 1.1;
};

上面代码通过module.exports对象,定义了一个函数,该函数就是模块外部与内部通信的桥梁。

加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的module.exports对象。

CommonJS 规范:http://javascript.ruanyifeng.com/nodejs/commonjs.html

RequireJS和SeaJS

RequireJS由James Burke创建,他也是AMD规范的创始人。

define方法用于定义模块,RequireJS要求每个模块放在一个单独的文件里。

RequireJS 和 Sea.js 都是模块加载器,倡导模块化开发理念,核心价值是让 javascript 的模块化开发变得简单自然。

SeaJSRequireJS最大的区别:

SeaJS对模块的态度是懒执行, 而RequireJS对模块的态度是预执行

不明白?看这篇图文并茂的文章吧:http://www.douban.com/note/283566440/

RequireJS API:http://www.requirejs.cn/docs/api.html

RequireJS的用法:http://www.ruanyifeng.com/blog/2012/11/require_js.html

为什么要用requireJS

试想一下,如果一个网页有很多的js文件,那么浏览器在下载该页面的时候会先加载js文件,从而停止了网页的渲染,如果文件越多,浏览器可能失去响应。其次,要保证js文件的依赖性,依赖性最大的模块(文件)要放在最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。

RequireJS就是为了解决这两个问题而诞生的:

(1)实现js文件的异步加载,避免网页失去响应;
(2)管理模块之间的依赖性,便于代码的编写和维护。

RequireJS文件下载:http://www.requirejs.cn/docs/download.html

AMD和CMD

CMD(Common Module Definition) 通用模块定义。该规范明确了模块的基本书写格式和基本交互规则。该规范是在国内发展出来的。AMD是依赖关系前置,CMD是按需加载。

在 CMD 规范中,一个模块就是一个文件。代码的书写格式如下:

define(factory);

factory 为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:require、exports 和 module:

define(function(require, exports, module) {// 模块代码});

require是可以把其他模块导入进来的一个参数,而export是可以把模块内的一些属性和方法导出的。
CMD规范地址:https://github.com/seajs/seajs/issues/242

AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。

对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。

AMD:提前执行(异步加载:依赖先执行)+延迟执行
CMD:延迟执行(运行到需加载,根据顺序执行)

CMD 推崇依赖就近,AMD 推崇依赖前置。看如下代码:

// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此处略去 100 行
var b = require('./b') // 依赖可以就近书写
b.doSomething()
// ... 
})// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
a.doSomething()
// 此处略去 100 行
b.doSomething()
...
}) 

另外一个区别是:

AMD:API根据使用范围有区别,但使用同一个api接口
CMD:每个API的职责单一

AMD的优点是:异步并行加载,在AMD的规范下,同时异步加载是不会产生错误的。
CMD的机制则不同,这种加载方式会产生错误,如果能规范化模块内容形式,也可以

jquery1.7以上版本会自动模块化,支持AMD模式:主要是使用define函数,sea.js虽然是CommonJS规范,但却使用了define来定义模块
所以jquery已经自动模块化了

seajs.config({'base':'/','alias':{'jquery':'jquery.js'//定义jQuery文件}
});

define函数和AMDdefine类似:

define(function(require, exports, module{//先要载入jQuery的模块var $ = require('jquery');//然后将jQuery对象传给插件模块require('./cookie')($);//开始使用 $.cookie方法});

sea.js如何使用?

  • 引入sea.js的库

  • 如何变成模块?

    • define

  • 3.如何调用模块?

         -exports-sea.js.use
  • 4.如何依赖模块?

         -require<script type="text/javascript">define(function (require,exports,module) {//exports : 对外的接口//requires : 依赖的接口require('./test.js');//如果地址是一个模块的话,那么require的返回值就是模块中的exports})

    </script>

sea.js 开发实例

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>鼠标拖拽的模块化开发实践</title>
<style type="text/css">
#div1{ width:200px; height:200px; background:black; position:absolute; display:none;}
#div2{ width:30px; height:30px; background:yellow; position:absolute; bottom:0; right:0;}
#div3{ width:100px; height:100px; background:blue; position:absolute; right:0; top:0;}
</style>
<script type="text/javascript" src="./sea.js"></script>
<script type="text/javascript">//A同事 :
seajs.use('./main.js');</script>
</head><body>
<input type="button" value="确定" id="input1" />
<div id="div1"><div id="div2"></div>
</div>
<div id="div3"></div>
</body>
</html>

A同事

//A同事写的main.js:define(function (require,exports,module) {var oInput = document.getElementById('input1');var oDiv1 = document.getElementById('div1');var oDiv2 = document.getElementById('div2');var oDiv3 = document.getElementById('div3');require('./drag.js').drag(oDiv3);oInput.onclick = function () {oDiv1.style.display = 'block';require('./scale.js').scale(oDiv1,oDiv2);require.async('./scale.js', function (ex) {ex.scale(oDiv1,oDiv2);})}
});

B同事


//B同事写的drag.js:define(function(require,exports,module){function drag(obj){var disX = 0;var disY = 0;obj.onmousedown = function(ev){var ev = ev || window.event;disX = ev.clientX - obj.offsetLeft;disY = ev.clientY - obj.offsetTop;document.onmousemove = function(ev){var ev = ev || window.event;var L = require('./range.js').range(ev.clientX - disX , document.documentElement.clientWidth - obj.offsetWidth , 0 );var T = require('./range.js').range(ev.clientY - disY , document.documentElement.clientHeight - obj.offsetHeight , 0 );obj.style.left = L + 'px';obj.style.top = T + 'px';};document.onmouseup = function(){document.onmousemove = null;document.onmouseup = null;};return false;};}exports.drag = drag;//对外提供接口});

C同事

//C同事写的scale.js:define(function(require,exports,module){function scale(obj1,obj2){var disX = 0;var disY = 0;var disW = 0;var disH = 0;obj2.onmousedown = function(ev){var ev = ev || window.event;disX = ev.clientX;disY = ev.clientY;disW = obj1.offsetWidth;disH = obj1.offsetHeight;document.onmousemove = function(ev){var ev = ev || window.event;var W = require('./range.js').range(ev.clientX - disX + disW , 500 , 100);var H = require('./range.js').range(ev.clientY - disY + disH , 500 , 100);obj1.style.width = W + 'px';obj1.style.height = H + 'px';};document.onmouseup = function(){document.onmousemove = null;document.onmouseup = null;};return false;};}exports.scale = scale;});

D同事

// D同事的range.js--限定拖拽范围define(function(require,exports,module){function range(iNum,iMax,iMin){if( iNum > iMax ){return iMax;}else if( iNum < iMin ){return iMin;}else{return iNum;}}exports.range = range;});

requirejs开发实例

require.config是用来定义别名的,在paths属性下配置别名。然后通过requirejs(参数一,参数二);参数一是数组,传入我们需要引用的模块名,第二个参数是个回调函数,回调函数传入一个变量,代替刚才所引入的模块。

main.js文件

//别名配置
requirejs.config({paths: {jquery: 'jquery.min' //可以省略.js}
});
//引入模块,用变量$表示jquery模块
requirejs(['jquery'], function ($) {$('body').css('background-color','red');
});

引入模块也可以只写require()requirejs通过define()定义模块,定义的参数上同。在此模块内的方法和变量外部是无法访问的,只有通过return返回才行.

define 模块

define(['jquery'], function ($) {//引入jQuery模块return {add: function(x,y){return x + y;}};
});

将该模块命名为math.js保存。

main.js引入模块方法

require(['jquery','math'], function ($,math) {console.log(math.add(10,100));//110
});

没有依赖

如果定义的模块不依赖其他模块,则可以:

define(function () {return {name: "trigkit4",age: "21"}
});

AMD推荐的风格通过返回一个对象做为模块对象,CommonJS的风格通过对module.exportsexports的属性赋值来达到暴露模块对象的目的。

http://www.cnblogs.com/simpro/p/4935125.html

https://segmentfault.com/a/1190000000733959


http://chatgpt.dhexx.cn/article/NtC4cC1y.shtml

相关文章

深入理解JavaScript模块化开发

前言&#xff1a; 随着JavaScript应用程序的复杂性不断增加&#xff0c;模块化开发成为了一种必备的技术。通过将代码划分为模块&#xff0c;我们可以提高代码的可维护性、可重用性和可扩展性。在本文中&#xff0c;我们将深入探讨JavaScript模块化开发的概念、优势和不同的模块…

细说前端模块化开发

一、模块化概述 模块化开发是当下最重要的前端开发范式之一。随着前端应用的日益复杂&#xff0c;我们的项目代码已经逐渐膨胀到了不得不花大量时间去管理的程度了。模块化就是一种最主流的代码组织方式&#xff0c;它通过把我们的复杂代码按照功能的不同&#xff0c;划分为不…

模块化开发简述

模块化开发简述 都说模块化开发为前端发展带来了巨大的进步&#xff0c;然而不熟悉的人看着也是两眼一懵&#xff0c;那其实这到底是什么&#xff1f;好处在哪&#xff1f;我来说说自己的见解吧。 1. 模块化和传统开发的区别 实话讲&#xff0c;其实在我看来&#xff0c;两…

什么是模块化?模块化怎么实现?

什么是模块化&#xff1f;模块化怎么实现&#xff1f; 前言 &#xff1a; 增加印象&#xff0c;留下脚印 &#xff0c;忘记还可以翻一翻 奥利给。 1&#xff0c;什么是模块化 公司里一个项目是有很多程序员一起开发的&#xff0c;例如 “多人运动” 这个项目 有程序员a &…

vue 模块化开发

1、npm install webpack -g 全局安装 webpack 2、npm install -g vue/cli-init 全局安装 vue 脚手架 3、初始化 vue 项目&#xff1b; vue init webpack appname&#xff1a;vue 脚手架使用 webpack 模板初始化一个 appname 项目 4、启动 vue 项目&#xff1b; 项目的 p…

Android模块化开发

模块化开发项目搭建 1.为什么要模块化开发 随着APP版本不断的迭代&#xff0c;新功能的不断增加&#xff0c;业务也会变的越来越复杂&#xff0c;APP业务模块的数量有可能还会继续增加&#xff0c;而且每个模块的代码也变的越来越多&#xff0c;这样发展下去单一工程下的APP架…

vue模块化开发

1.前端代码化雏形和CommonJS JavaScript原始功能 在网页开发的早期&#xff0c;js制作作为一种脚本语言&#xff0c;做一些简单的表单验证或者动画实现&#xff0c;代码量比较少&#xff0c;只要写在script标签里面就可以了 随着ajax异步请求的出现&#xff0c;慢慢形成了前…

模块化编程

1.一般编程方式&#xff1a;所有函数放在“.c”文件里。 &#xff08;缺点&#xff1a;若使用的模块功能比较多&#xff0c; 则一个文件内会有很多的代码&#xff0c; 不…

一次跟你说清楚,什么是组件化开发?什么是模块化开发?

网上有许多讲组件化开发、模块化开发的文章&#xff0c;但大家一般都是将这两个概念混为一谈的&#xff0c;并没有加以区分。而且实际上许多人对于组件、模块的区别也不甚明了&#xff0c;甚至于许多博客文章专门解说这几个概念都有些谬误。 想分清这两个概念我觉得结合一下软件…

前端模块化开发

前端模块化开发 什么是模块化&#xff1f; 模块化是指解决一个复杂问题时&#xff0c;自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说&#xff0c;模块是可组合、分解和更换的单元 编程领域中的模块化&#xff0c;就是遵守固定的规则&#xff0c;把一个大文件拆成…

模块化开发

模块化开发 1. 模块化开发最终的目的是将程序划分成 一个个小的结构 。 2. 这个结构中编写属于 自己的逻辑代码 &#xff0c;有 自己的作用域 &#xff0c;定义变量名词时不会影响到其他的结构。 3. 这个结构可以将自己希望暴露的 变量、函数、对象等导出 给其结构使用&#xf…

HttpClient CloseableHttpClient GetMethod PostMethod http

pom依赖 <!--HttpClient的依赖--><dependency><groupId>commons-httpclient</groupId><artifactId>commons-httpclient</artifactId><version>3.1</version></dependency><!--CloseableHttpClient的依赖--><de…

JAVA小工具-05-HttpClient/PostMethod上传文件(解决中文文件名乱码问题)

言于头:本节讨论的是在项目中利用HttpClient/PostMethod相关api进行上传文件操作时&#xff0c;会出现上传中文文件名乱码问题。为解决这个问题&#xff0c;下面是总结的一个HTTP工具类以及测试用例。 public class HttpUtils {public static final String UTF_8 "UTF-8&…

解决PostMethod的中文乱码

解决HttpClient的PostMethod的中文乱码问题 问题场景&#xff1a; 解决代码&#xff1a; 请求时设定编码格式&#xff1a; post.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8"); 完整代码&#xff1a; /*** 封装请求参数&#xff0…

php 取整,PHP取整的方法有哪些

本篇文章主要给大家介绍PHP取整的四种方法。 PHP实现取整的问题&#xff0c;不仅在我们学习PHP过程中会遇到&#xff0c;在我们PHP面试过程中也是常见的考点之一。 下面我们结合简单的示例给大家总结介绍PHP取整的四种方法。 第一种方法&#xff1a;直接取整&#xff0c;舍弃小…

php 如何取整,解析php取整的几种方式

解析php取整的几种方式 floor 舍去法取整 语法格式:float floor ( float value )返回不大于value 的下一个整数&#xff0c;将value 的小数部分舍去取整。floor() 返回的类型仍然是float&#xff0c;因为float 值的范围通常比integer 要大。 echo floor(4.3); // 4 echo floo…

VUE 数据分页

只要涉及到数据查询&#xff0c;通常我们都会进行分页查询。 假设你的表中有上百万条记录&#xff0c;不分页的话&#xff0c;我们不可能一次性将所有数据全部都载入到前端吧&#xff0c;那前后端都早就崩溃了。 结合 Spring Spring 和 Vue 都提供了开箱即用的分页功能。 S…

前端Vue分页及后端PageHelper分页综合运用

分页显示数据对项目开发中尤为重要&#xff0c;同时能提升用户体验&#xff0c;下面的前端css、js是我引用这篇文章的《使用Vue开发一个分页插件》&#xff0c;我在这个的基础上结合了后端稍微完善了一下&#xff0c;修改了disable的样式&#xff0c;在里面加了pointer-events:…

antd design vue分页组件

我们在使用分页组件的时候可以有两种方法&#xff1a; 第一种是直接用表格()的自定义:pagination属性最方便&#xff1b;如下图所示&#xff1a; 第二种是分页组件 这里我总结的是第二种方法的使用&#xff0c;由于是 Ant Design Vue 的组件&#xff0c;所以必须安装Ant Desig…

Vue分页页码栏设计

Vue分页页码栏设计 效果展示HTML数据需要函数需要运用 效果展示 HTML <div class"page_bar no-select"><ul class"clearfix"><li class"iconfont":class"{vh : currentPage 1}"click"subCurrentPage">&…