一、無模塊化的時代
1.命名的衝突
2.文件依賴
二、初步解決無模塊化的bug
1.全局函數
就是將重複的代碼放在函數中,再將一系列函數放在一個js文件中,這個文件中的所有函數就是一個特定功能的實現,這個文件就是一個模塊
缺點 :污染全局變量,模塊成員之間看不出直接關係。
2.對象命名空間
形式上解決了命名衝突問題,但並不能從根本上解決
缺點:內部狀態可被外部改寫。
3.私有公有成員分離 ,
就是執行函數,私有的變量和函數不會影響到全局作用域
雖然解決了變量命名衝突的問題
(function(root){
// 私有
var num=1;
// 公有
root.run=function(){
console.log(num);
}
})(this);
總之,以上三個方法並沒有解決開發複雜度的問題。
三、Common.JS 模塊化時代
1.服務器端(如node.js)使用Common.js, 它是同步的
//foo.js文件
var x = 5;
var addX = function (value) {
return value + x;
};
// 三種方式導出接口
module.exports.x = x;
module.exports.addX = addX;
// exports.x=x;
// exports.addX=addX;
// module.exports={
// x:x,
// addX:addX
// }
// 而這個導出接口不對
// module.exports = x;
// module.exports = addX;
//nodeTest.js文件
var example = require('./foo.js');
console.log(example.x); // 5
console.log(example.addX(1)); // 6
2.CommonJS模塊的特點:
所有代碼都運行在模塊作用域,不會污染全局作用域。
模塊可以多次加載,但是只會在第一次加載時運行一次,然後運行結果就被緩存了,以後再加載,就直接讀取緩存結果。要想讓模塊再次運行,必須清除緩存。
模塊加載的順序,按照其在代碼中出現的順序。
一個模塊就是一個文件,一個模塊就是module對象,這個module對象就是node內部的Module構造函數new出來的實例。
module.exports屬性表示當前模塊對外輸出的接口,其他文件加載該模塊,實際上就是讀取module.exports變量。
3.CommonJS規範和AMD規範的區別
CommonJS規範加載模塊是同步的,也就是說,只有加載完成,才能執行後面的操作。
AMD規範則是異步加載模塊,允許指定回調函數。由於Node.js主要用於服務器編程,模塊文件一般都已經存在於本地硬盤,所以加載起來比較快,不用考慮非同步加載的方式,所以CommonJS規範比較適用。但是,如果是瀏覽器環境,要從服務器端加載模塊,這時就必須採用異步模式,因此瀏覽器端一般採用AMD規範。
4.CommonJS模塊的加載機制
是:輸入的是被輸出的值的拷貝。也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。
四、Require.js模塊化時代( AMD)
1. 瀏覽器端使用Require.js, 它異步的
2.AMD是異步模塊定義,它採用異步方式加載模塊,通過define方法去定義模塊,require方法去加載模塊
define([依賴的模塊1,依賴的模塊1],function(){
})
require([加載的模塊1,加載的模塊1],function(){
//require參數一異步加載模塊1.模塊2成功後纔會執行require參數二回調函數,這樣瀏覽器不會失去響應,解決了依賴性問題
}
//b.js 文件
define(function(){
var name='xtt';
return {
name:name
}
})
// a.js文件
define(['b'],function(b){
console.log(b); //{name:"xtt"}
var Hello=function(){
console.log('hello world');
}
return { //接口對象
Hello:Hello
}
//這兩者不可以導出接口對象
// module.exports={Hello:Hello};
// exports.Hello=Hello;
})
//test.html
<script src="./require.js"></script>
<script>
require(['a', 'b'], function (a, b) {
console.log(a);
console.log(b);
})
</script>
五、Sea.js模塊化時代(CMD)
1. 瀏覽器端使用Sea.js, 它異步的
2.CMD 即通用模板定義,CMD規範是國內發展起來的;
define(function(require,exports,module){
// 模塊代碼
//require:是可以把其他模塊導入進來的一個參數;
//exports:可以把模塊內的一些屬性和方法導出;
//module是一個對象,上面存儲了與當前模塊相關聯的一些屬性和方法
CMD推崇依賴就近,延遲執行。文件是提前加載好的,只有在require的時候纔去執行文件
})
//b.js文件
define(function(require,exports,module){
exports.max='xtt';
});
//a.js文件
define(function(require,exports,module){
var b=require('b');
console.log(b);
// 下面三種方式均可以導出接口
exports.Hello=function(){
console.log('hello work');
}
// module.exports={
// Hello:function(){
// console.log('hello work');
// }
// }
// return {
// Hello:function(){
// console.log('hello work');
// }
// }
});
//test.html文件
<script src="./sea.js"></script>
<script>
// 配置
seajs.config({
alias:{
'a':'./a',
'b':'./b'
}
});
// 啓動模塊加載器
seajs.use(['a','b'],function(a,b){
console.log(a);
console.log(b);
});
</script>
六、ES6 module模塊化時代(重點)
1.export用於把模塊裏的內容暴露出去
2.import用於引入模塊提供的功能
3.可以使用export default命令,爲模塊指定默認輸出,一個模塊只能有一個默認輸出,所以export default只能使用一次
4.ES6模塊是動態引用,如果使用import從一個模塊加載變量(即 import foo from 'foo'),變量不會被緩存,而是成爲一個指向被加載模塊的引用。等腳本執行時,根據只讀引用,到被加載的那個模塊中去取值。
5.ES6支持瀏覽器端也支持node端