最近在面试以及工作中因为经常会涉及到模块化的问题,就去查了模块化的相关资料,今天就来大致的做一个总结。
为什么会有模块化的出现呢?
首先,在早期时,javascript是没有模块化的定义的,后面代码量增多了就得分成多个文件,需要依次加载js文件(如下所示)
<script src="1.js"></script>
......
<script src="2.js"></script>
这种写法的缺点就是,因为浏览器中加载js引擎和渲染引擎之间是互斥的,加载js时会停止渲染网页,如果加载时间过程很可能会导致白屏现象,其次如果各个文件之间有依赖,就必须按照顺序来执行,后期也会难以维护。
AMD
AMD--"Asynchronous Module Definition"(异步模块定义)。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。 AMD规范通过define方法去定义模块,通过require方法去加载模块。下面代码贴出它的相关用法:
```//独立模块(module1.js)
define({
method1: function() {
console.log('我是module1');
},
method2: function() {
console.log('我是module2')
},
});
//第二种写法:作为函数return出去(module2.js)
define(function () {
return {
method1: function() {
console.log('我是module1');
},
method2: function() {
console.log('我是module2')
},
};
});
//非独立组件,依赖于其他组件,第一个参数是一个数组(包含其依赖的模块),第二个参数是一个函数
define(['module1', 'module2'], function(m1, m2) {// 依赖必须一开始就写好
return{
module:function(){
m1.methodA();
..........
m2.methodB();
}
}
});
//定义一个main.js,去加载这些模块
define(['module2'],function(m2){
m2.method3();
})
CMD
CMD--"Common Module Definition",在CMD规范里面,一个模块就是一个Javascript文件。
define(function(require, exports, module) {
var a = require('module1')
a.method1()
.......
var b = require('module2') // 依赖可以就近书写
b.method1()
})
AMD与CMD的区别
- 以上我们可以从代码中看出对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible。(尽可能的懒加载)
- CMD 推崇依赖就近,AMD 推崇依赖前置。(从代码中可以看出)
CommonJS
CommonJS规范,一个单独的文件就是一个模块。CommonJS是2009年由JavaScript社区提出的包含了模块化的一个标准,后来被Node.js所采用并实现,也就是说我们在Node.js中用到的模块导入导出都是依照CommonJS标准来实现的。
var md=function(){
console.log('hello,commonjs');
}
// 1.通过exports.xxx = xxx导出 exports.test=md
// 2.通过module.exports.xxx = xxx导出 module.exports.test=md
exports.test=md
//同目录下新建一个test.js文件
var module=require("./module");
//调用
module.test();
//执行
node test.js
ES6 Module
JavaScript在ES6加入了模块(module)体系的语法,ES6主要提供两个命令export和import,用于模块向外提供接口(export)和引入其他模块接口(import)。
//导出(A.js)
let a=1
function fn(){}
//1.命名导出
export{a,fn}//批量导出
export let a=1
export function fn(){}//单个的导出
//2.默认导出
export default fn
//导入(B.js)
import {fn, a} from './A.js'
import {fn as fn1, a as count} from './A.js'//(通过as来进行重命名)
import * as module from './A.js'//(通过*来整体导出,并赋值给module,再通过module来调用)
import fn1 from './A.js'//(针对默认导出的对象,所以只能有一个默认导出的对象)
ES6 Module与CommonJS的区别
- 对于模块的依赖,CommonJS是动态的(运行时加载),ES6 Module 是静态的(编译时输出接口)
- CommonJS导入的是值的拷贝(拷贝后的值改变不会影响之前值的改变),ES6 Module导入的是值的引用(会影响之前的值)
- CommonJSthis指向当前模块,ES6 Modulethis指向undefined;
最后:本文只是做一个大致介绍,纯属记录个人笔记,也引用了网上的相关资料,更多细节感兴趣的可以自行查阅资料,小白第一次写文章,若有不妥的地方欢迎吐槽。