前端模块化
一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范。
1、AMD规范
AMD(Asynchronous Module Definition,即异步模块加载机制):推崇依赖前置,在定义模块的时候就要声明其依赖的模块
所有模块都加载执行完后会进入require的回调函数。由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数,也就是RequireJS,实际上AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出。requireJS定义了一个函数 define,它是全局变量,用来定义模块。
requireJS主要解决两个问题
- 多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
- js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长
例子:
// 模块定义函数
// 依赖项(foo 和 bar)被映射为函数的参数
define('myMoudle',['foo','bar'],function(foo,bar){
// 返回一个定义了模块导出接口的值
// (也就是我们想要导出后进行调用的功能)
// 在这里创建模块
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
}
return myModule;
});
或者
define('myModule',['math', 'graph'], function ( math, graph ) {
return {
plot: function(x, y){
return graph.drawPie(math.randomGrid(x,y));
}
}
};
});
2、CMD规范
CMD(Common Module Definition,即通用模块定义)推崇就近依赖,只有在用到某个模块的时候再去require
CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块。CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同。
在CMD中 一个模块就是一个文件
注意:带有id 和 deps 是不属于CMD规范的。所以在seaJS里面 一般的写法是不带模块名称和依赖项的
例子:
require 是一个方法,用来获取其他模块提供的接口
exports 是一个对象,用来向外提供模块接口
module 是一个对象,上面存储了与当前模块相关联的一些属性和方法
//基本格式如:define(id, deps, factory)
//id(模块名称)和deps(被依赖项) 是可以省略的。省略时,那么模块名称就是文件名称
// 比如如下代码
define('hello',['jQuery'],function(require, exports, module) {
// 模块代码
});
define(function(require, exports) {
console.log(require.resolve('./b'));
// ==> http://example.com/path/to/b.js
exports.a = function(){
// 很多代码
};
});
3、AMD与CMD的区别
1.CMD依赖就近,而AMD依赖前置
2. 执行顺序上:CMD是延迟执行的,而AMD是提前执行的
3. api设计角度:AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。
4、CommonJS规范(同步加载模块)
CommonJS是服务器端模块的规范,Node.js采用了这个规范.Node.JS首先采用了js模块化的概念.
CommonJS定义的模块分为:模块引用(require)/ 模块定义(exports)/模块标识(module)
前端的webpack
也是对CommonJS原生支持的
CommonJS:非浏览器-同步,导出的内容只能包含在一个对象中,导出的内容是值拷贝
CommonJS的核心思想就是通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或者 module.exports 来导出需要暴露的接口
// a.js
var x = 5;
var addX = function (value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
浏览器不兼容CommonJS的根本原因,在于缺少四个Node.js环境的变量。
- module
- exports
- require
- global
5、ES6模块化
使用 import 关键字引入模块,通过 export 关键字导出模块
default 是 ES6 Module 所独有的关键字
一个模块只能有一个默认导出,对于默认导出,导入的名称可以和导出的名称不一致
由于ES6目前无法在浏览器中执行,所以,我们只能通过babel将不被支持的import编译为当前受到广泛支持的 require。
import store from '../store/index'
import {mapState, mapMutations, mapActions} from 'vuex'
import axios from '../assets/js/request'
import util from '../utils/js/util.js'
export default {
created () {
this.getClassify();
this.RESET_VALUE();
console.log('created' ,new Date().getTime());
}
6、CommonJS与ES6的区别
- Commonjs是拷贝输出,ES6模块化是引用输出
- Commonjs是运行时加载,ES6模块化是编译时输出接口
- Commonjs是单个值导出,ES6模块化可以多个值导出
- CommonJS模块是对象,而ES6模块可以是任何数据类型
- Commonjs是动态语法可写在函数体中,ES6模块化静态语法只能写在顶层
- Commonjs的this是当前模块化,ES6模块化的this是undefined
- ES5 的 CommonJS:require/exports 的写法; ES6的Module:import/export的写法