模塊化開始如今已經很流行了,方便代碼的管理,一般一個文件就是一個模塊,有本身的做用域,只是向外暴露特定的變量或者函數
目前流行的js模塊化規範就有 CommonJS AMD CMD ES6 模塊系統,這個總結 是看別人的原始出處在 掘金APP 上;
一: CommonJS
Node.js是commonJS規範的主要實踐者,它有四個重要的環境變量爲模塊化的實現提供支持:module exports require global
用module.exprots定義當前模塊對外輸出的藉口 用require加載模塊
定義math.js文件
var basicNum = 0;
function add(a,b){
javascript
return a+b;
};
module.exports = {add:add,basicNum:basicNum}; //對象輸出特定變量
//文件引入
var math = require('./math');
math.add(2,3);
//文件引入核心模塊時候不須要帶路徑
var http = require('http');
http.createSevise(...).listen(3000);
CommonJS 用同步的方式加載模塊,在服務器端模塊文件都是在本地磁盤上,讀取很是快,可是在瀏覽器端限於網絡緣由,更適合用異步加載
二: AMD和require.js
AMD規範採用異步方式加載模塊,模塊的加載不影響它後面的語句執行,全部依賴這個模塊語句都定義在一個函數回調中,
等到加載完成以後,纔開始執行回調函數,用require.config()指定引用路徑 用define()定義模塊 用require加載模塊
首先咱們須要引入require.js文件和一個入口文件main.js 在main.js中配置require.config()並規定項目中用到的基礎模塊
//在網頁中引入require.js和main.js
<script src="js/require.js" data-main="js/main"></script>
//在main.js入口文件 首先定義config()指定各模塊路徑和引用名
require.config({
baseUrl: 'js/lib',
paths: {
'require': 'jquire.main' //實際路徑爲 js/lib/jquire.main.js
'underscore': 'underscore.main'
}
});
//執行基本操做
require(['jquire','underscore'],function($,...){
//some code here
});
引用模塊時候,咱們講模塊名放在[]中做爲require()第一參數,若是咱們定義的模塊自己也依賴其餘模塊,那就須要將他們放在[]中做爲define()第一參數,html
若是咱們定義的模塊自己也依賴其餘模塊,那就須要將他們放在
//定義main.js模塊
define(function(){
var basicNum = 0;
var add = function(x,y){
return x+y;
};
return {
add : add,
basicNum : basicNum
};java
});
//定義一個依賴underscore.js模塊
define(['underscore'],function(_){
var classify = function(list){
-.countBy(list,function(num){
return num > 20 ? 'old' : 'young';
});
}
return {
classify:classify
}
});
//引用模塊,將模塊放在[]內
require(['jquire','main'],function($,math){
var sum = math.add(2,3);
$("#sum").html(sum);
});
三:CMD和sea.js
require.js在聲明依賴模塊時會第一之間加載並執行模塊內的代碼;
define(['a','b','c'],function(a,b,c){
//等於在最前面聲明並初始化要用到的全部模塊
if(false){
//即使沒有用到某個模塊b,但b仍是提早執行了
b.foo();
}
});
CMD是另外一個js模塊化方案,和AMD很相識,不一樣點在於:AMD推崇依賴前置,提早執行,CMD推崇依賴就近,延遲執行,在sea.js中推廣中產生的
//CMD寫法:
define(function(require,exports,module){
var a = require('./a'); //在須要時候聲明
a.doSomething();
if(false){
var b = require('./b');
b.doSomething()
}
});
//sea.js
//定義模塊main.js
define(function(require,exports,module){
var $ = require('jquire.js');
var add = function(a,b){
return a+b;
};
exports.add = add;
});
//加載模塊
seajs.use(['main.js'],function(){
var sum = math.add(1+1);
});
四:ES6 Module
ES6在語言標準的層面上,實現了模塊功能,並且實現得至關簡單,旨在瀏覽器和服務器通用的模塊解決方案,
其主要構成是:export和import,export命令用於規定模塊的對外接口,import命令用於輸入其餘模塊提供功能
//定義模塊main.js
var basicNum = 0;
var add = function(a,b){
return a+b;
};
export({basicNum,add});
//引用模塊
import {basicNum,add} from './main'
function test(ele){
ele.testCont = add(2+basicNum);
};
若是用export default{basicNum,add}; 不用使用大括號
//定義輸出
export default{basicNum,add};
//引入
import math from './main';
function test(ele){
ele.testCont = math.add(99+math.basicNum);
}
ES6模塊不是對象,import命令會被javascript引擎靜態分析,在編譯時引入模塊代碼,而不是在代碼運行時候加載,因此沒法實現條件加載
也是這個緣由,使得靜態分析成爲可能
五:ES6模塊與CommonJS模塊的差別
1.CommonJS模塊輸出的是一個值得拷貝,ES6模塊輸出的值得引用
CommonJS模塊輸出是一個值得拷貝,也就是說一旦輸出一個值,模塊內部變化就影響不到這個值
ES6模塊運行機制,JS引擎對腳本靜態分析的時候,遇到模塊加載命令import,就會生成一個只讀引用,等到腳本真正執行時,再根據
這個只讀引用到被加載的那個模塊裏面去取值, import加載的值也會跟着變,所以ES6模塊是動態引用,而且不會緩存值
2.CommonJS模塊是運行時加載,ES6模塊是編譯時輸出接口
運行時加載:CommonJS模塊就是對象,即在輸入時是先加載整個對象,生成一個對象,而後再從這個對象上讀取方法,這種稱爲:運行時加載
編譯時加載:ES6模塊不是對象,而是經過exprot命令顯示指定輸出的代碼,import時採用靜態命令形式,而不是加載整個模塊 這種稱爲:編譯時加載
CommonJS加載是一個對象 (module.exprots屬性) 而ES6模塊不是對象,它的對外接口是一種靜態定義,在代碼靜態解析階段會生成瀏覽器