什么是模块化?
模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元.
编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块,是将不同功能的函数封装起来,并提供使用接口,他们彼此之间互不影响,想要什么功能,就加载什么模块,可以实现按需加载。
简单来说,模块化就是把系统分割成独立的功能块,提高代码的复用性。
模块化开发的意义
优点:
-
便于多人协作开发,每个部分开发不会干扰其它地方 ,降低了耦合性
-
便于调试修改,因为模块独立,发现问题比较容易,修改一处,也不影响别处,利于前端性能优化.
-
利于代码复用,小块的代码可以更方便拿到别的项目中不加或者稍加修改使用,提高可维护性.
-
便于功能的扩充,因为软件各个部分是独立的,不需要理解整个软件就可以添加功能,适合二次开发.
-
解决了部分恼人的命名冲突以及烦琐的文件依赖.
缺点:
1.系统分层,调用链会很长
2.模块间通信,模块间发送消息会很耗性能
模块化的意义在于最大化的设计重用,以最少的模块、零部件,更快速的满足更多的个性化需求。
模块化开发的一些规范
1. CommonJS
这个规范是node的规范,在此之后前端的模块化发展迅速.许多的主流前端框架都是都是由node基于搭建
使用require
导入内置的包或者导入自己写的文件,导入本地的包时记得用./
表示文件路径,核心模块不需要
CommonJS规范(运行时)
1、每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
2、在模块中使用global 定义全局变量,不需要导出,在别的文件中可以访问到。
3、每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。
4、通过 require加载模块,读取并执行一个js文件,然后返回该模块的exports对象。
5、所有代码都运行在模块作用域,不会污染全局作用域。
6、模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
7、模块加载的顺序,按照其在代码中出现的顺序。
2. ESM(编译时)
在 ES Module 中用 export 用来导出模块,import 用来导入模块。CommonJS 模块同步加载并执行模块文件,ESM 模块提前加载并执行模块文件,ESM模块在预处理阶段分析模块依赖,在执行阶段执行模块,两个阶段都采用深度优先遍历.其实就是客户端的导出规范.
CommonJS 输出的是一个值的拷贝;ES Modules 生成一个引用,等到真的需要用到时,再到模块里面去取值,模块里面的变量,绑定其所在的模块。以后需要用到这个模块的时候,就会到exports属性上面取值。即使再次执行require命令,也不会再次执行该模块,而是到缓存之中取值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
node中使用这种导入模式需要把后缀改为mjs
ESM导入规则
1.导入变量名
import greet from './greeting.js';
2.解构导出
import { add, subtract } from './math.js';
3.全部导出
import * as math from './math.js';
3. AMD规范(requirejs)
AMD的核心是预加载,先对依赖的全部文件进行加载,加载完了再进行处理。
适合在浏览器环境中异步加载模块。可以并行加载多个模块。 并可以按需加载。核心就是前端的require.js包的学习.
使用
src引入requirejs,date-main将main模块为主模块加载
官方网址: https://requirejs.org
4. CMD规范(seajs)
即通用模块定义。按需加载。在 CMD 规范中,一个模块就是一个文件,使用define来进行模块,define是一个全局函数。 factory 可以是一个函数,也可以是一个对象或字符串。
使用
js
define({'website':'oecom'});
define('这里是OECOM');
define(function(require,exports,module){
})
js
require参数也是一个方法,接收的参数为模块标识,其实就是需要加载模块的相对路径,作用就是加载其他模块。
define(function(require,exports,module){
var a = require('./a');
//假设模块a有out方法。
a.out();
})
直接使用require加载属于是同步加载,require提供了async方法来在模块内部进行也不加载模块,并在加载完成以后执行指定的回调函数。
define(function(require,exports,module){
require.async('./a',function(a){
a.doSomething()
})
require.async(['./c','./b'],function(c,b){
c.doSomething()
b.doSomething()
})
}
require 是同步往下执行,require.async 则是异步回调执行。require.async 一般用来加载可延迟异步加载的模块。
exports是一个用来想外接提供模块接口的对象
define(function(require,exports){
var name = 10;
exports.name = name;
exports.out = function(){
console.log("输出内容")
}
})
当然导出模块还可以直接使用return的方式
define(function(require){
return{
name:10,
out:function(){
console.log("输出内容")
}
}
})