Appearance
前端模块化就是复杂的文件编程一个一个独立的模块,比如 js 文件等等,分成独立的模 块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题,所 以有了 commonJS 规范,AMD,CMD 规范等等,以及用于 js 打包(编译等处理)的工具 webpack
CommonJS
NodeJS 是 CommonJS 规范的实现,webpack 也是以 CommonJS 的形式来书写
浏览器不能兼容,因为 require 是同步的,需要等待的,如果我们去使用同步获取服务器 信息,那么浏览器将会“假死”状态,并且浏览器也没有 module、exports、require、global 这四个 node 变量
CommonJS 定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识 (module)},运行时加载
转换工具: Browserify
//foo.js
module.exports = function(x) {
console.log(x);
};
//main.js
var foo = require("./foo");
foo("Hi");
========================》》》》》》
[
{
"id":1,
"source":"module.exports = function(x) {\n console.log(x);\n};",
"deps":{}
},
{
"id":2,
"source":"var foo = require(\"./foo\");\nfoo(\"Hi\");",
"deps":{"./foo":1},
"entry":true
}
]
browerify 将所有模块放入一个数组,id 属性是模块的编号,source 属性是模块的源码,deps 属性是模块的依赖。
AMD
异步模块定义,就是为了解决 commonjs 同步等待的问题,使用异步加载,不影响后面代码 的执行, AMD 也采用 require()语句加载模块,但是不同于 CommonJS,它要求两个参数:
// math.js
define(function (){
var add = function (x,y){
return x+y;
};
var ccc = function (x,y){
return x+y;
};
return {
add: add,
ccc:ccc
};
});
require(['math'], function (math) {
math.add(2, 3);
});
注意:如果定义的模块依赖于别的模块,那么第一个参数是一个依赖模块的数组,使用require.js的插件可以不一样写
define(['dep1','dep2'],function(dep1,dep2){...});
RequireJS就是实现了 AMD 规范,比如说在项目中使用 require.js,然后设置主入口 去异步加载别的模块
<script src="js/require.js" data-main="js/main"></script>
假定主模块依赖jquery、underscore和backbone这三个模块,main.js就可以这样写:
require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){
// some code here
});
或者
require.config({
baseUrl: "js/lib",
paths: {
"jquery": "jquery.min",
"underscore": "underscore.min",
"backbone": "backbone.min"
}
});
CMD/AMD
通用模块定义 seajs CMD 推崇依赖就近,AMD 推崇依赖前置 ,AMD 主张以来一开始加载 完毕,而 CMD 主张需要用到时才加载
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此处略去 100 行
var b = require('./b') // 依赖可以就近书写
b.doSomething()
// ...
})
AMD | 速度快 | 会浪费资源 | 预先加载所有的依赖,直到使用的时候才执行
CMD | 只有真正需要才加载依赖 | 性能较差 | 直到使用的时候才定义依赖
CommonJS 和 ES6 模块的区别
- CommonJS 模块是运行时加载,ES6 Modules 是编译时输出接口
- CommonJS 输出是值的拷贝;ES6 Modules 输出的是值的引用,被输出模块的内部的改变 会影响引用的改变
- CommonJs 导入的模块路径可以是一个表达式,因为它使用的是 require()方法;而 ES6 Modules 只能是字符串
- CommonJS this 指向当前模块,ES6 Modules this 指向 undefined
- 且 ES6 Modules 中没有这些顶层变量 :arguments、require、module、exports、**filename、**dirname
require
- CommonJs 的语法(AMD 规范引入方式),CommonJs 的模块是对象。
- 运行时加载整个模块(即模块中所有方法),生成一个对象,再从对象上读取它的方法 (只有运行时才能得到这 个对象,不能在编译时做到静态化),理论上可以用在代码的 任何地方
- require 是赋值过程,把 require 的结果(对象,数字,函数等),默认是 export 的 一个对象,赋给某个变量(复制或浅拷贝)