Javascript不是一種模塊化編程語言,它不支持"類"(class),更遑論"模塊"(module)了,隨着前端發展對 模塊需求愈來愈大,模塊也是經歷了從最初的簡單模塊寫法到AMD和CMD規範的出現,再到ES6發佈,目前已經能夠 很方便的在Javascript中使用"類"和"模塊"了。javascript
一、原始寫法html
function m1(){ //... } function m2(){ //... }
缺點 : "污染"了全局變量,沒法保證不與其餘模塊發生變量名衝突,並且模塊成員之間看不出直接關係。前端
二、對象寫法 爲了解決上面缺點,把模塊寫成一個對象,全部的模塊成員都放到這個對象裏面java
var module1 = new Object({ _count : 0, m1 : function (){ //... }, m2 : function (){ //... } });
使用node
module1.m1();
存在缺點: 可是,這樣的寫法會暴露全部模塊成員,內部狀態能夠被外部改寫。好比,外部代碼能夠直接改變內部計數器的值。jquery
module1._count = 5;
三、當即執行函數寫法webpack
當即執行函數(IIFE),能夠達到不暴露私有成員的目的。程序員
var module1 = (function(){ var _count = 0; var m1 = function(){ //... }; var m2 = function(){ //... }; return { m1 : m1, m2 : m2 }; })();
上面的寫法,外部代碼沒法讀取內部的_count變量。es6
console.info(module1._count); //undefined
四、放大模式 若是一個模塊很大,必須分紅幾個部分,或者一個模塊須要繼承另外一個模塊web
var module1 = (function (mod){ mod.m3 = function () { //... }; return mod; })(module1);
上面的代碼爲module1模塊添加了一個新方法m3(),而後返回新的module1模塊。
五、寬放大模式 在瀏覽器環境中,模塊的各個部分一般都是從網上獲取的,有時沒法知道哪一個部分會先加載。若是採用上一節的寫法,第一個執行的部分有可能加載一個不存在空對象,這時就要採用"寬放大模式"。
var module1 = ( function (mod){ //... return mod; })(window.module1 || {});
與"放大模式"相比,"寬放大模式"就是"當即執行函數"的參數能夠是空對象。
六、輸入全局變量 獨立性是模塊的重要特色,模塊內部最好不與程序的其餘部分直接交互。 爲了在模塊內部調用全局變量,必須顯式地將其餘變量輸入模塊
var module1 = (function ($, YAHOO) { //... })(jQuery, YAHOO);
上面的module1模塊須要使用jQuery庫和YUI庫,就把這兩個庫(實際上是兩個模塊)看成參數輸入module1 好處: 這樣作除了保證模塊的獨立性,還使得模塊之間的依賴關係變得明顯
談到AMD和CMD,不得不說下CommonJS。2009年,美國程序員Ryan Dahl創造了node.js項目,將javascript語言用於服務器端編程, 因爲瀏覽器端網頁還比較簡單 ,對於模塊不是特別依賴,但在服務器端由於要與操做系統和其餘應用程序互動,CommonJS 就在這樣的背景下誕生了。
引入第三方模塊並調用方法
var math = require('math'); math.add(2,3); // 5
這裏有一個CommonJS模塊使用的例子
//模塊定義 myModule.js var name = 'Byron'; function printName(){ console.log(name); } function printFullName(firstName){ console.log(firstName + name); } module.exports = { printName: printName, printFullName: printFullName } //加載模塊 var myModule = require('./myModule.js'); myModule.printName();
一、AMD規範
想象一下若是把這段代碼放到瀏覽器端 ,math.add(2, 3),在第一行require('math')以後運行,所以必須等math.js加載完成。也就是說,若是加載時間很長,整個應用就會停在那裏等
var math = require('math'); math.add(2, 3);
這對服務器端不是一個問題,由於全部的模塊都存放在本地硬盤,能夠同步加載完成,等待時間就是硬盤的讀取時間。可是,對於瀏覽器,這倒是一個大問題,由於模塊都放在服務器端,等待時間取決於網速的快慢,可能要等很長時間,瀏覽器處於"假死"狀態
所以,瀏覽器端的模塊,不能採用"同步加載"(synchronous),只能採用"異步加載"(asynchronous)
AMD也採用require()語句加載模塊,可是不一樣於CommonJS,它要求兩個參數
require([module], callback);
上面代碼改寫成AMD形式就是這樣
require(['math'], function (math) { math.add(2, 3); });
目前實現AMD規範的有RequireJS和curl.js
RequireJS模塊例子:
// 定義模塊 myModule.js define('myModule', ['dependency'], function(){ var name = 'Byron'; function printName(){ console.log(name); } return { printName: printName }; }); // 加載模塊 require(['myModule'], function (my){ my.printName(); });
二、CMD規範 CMD: Common Module Definition通用模塊定義, 由國內發展出來, SeaJS是其典型表明, 即SeaJS是經過瀏覽器對CMD的具體實現
SeaJS模塊例子:
// 定義模塊 myModule.js define(function(require, exports, module) { var $ = require('jquery.js'); var foo = require('foo'); var out = foo.bar(); $('div').addClass('active'); module.exports = out; }); // 加載模塊 seajs.use(['myModule.js'], function(my){ });
三、CommonJS、AMD和CMD區別
ES6在語言標準的層面上, 實現了模塊功能, 並且實現得至關簡單, 徹底能夠取代CommonJS和AMD規範, 是瀏覽器和服務器通用的模塊解決方案
ES6模塊例子:
//模塊定義 myModule.js const name = 'Byron'; function printName(){ console.log(name); } function printFullName(firstName){ console.log(firstName + name); } const myModule = { printName: printName, printFullName: printFullName }; export myModule; //加載模塊 import myModule, { printFullName } from './myModule.js'; myModule.printName(); printFullName('Michael');
說到 browserify / webpack ,那還要說到 seajs / requirejs 。這四個都是JS模塊化的方案。其中seajs / require 是一種類型,browserify / webpack 是另外一種類型。
一、seajs / require : 是一種在線"編譯"模塊的方案,至關於在頁面上加載一個 CMD/AMD 解釋器。這樣瀏覽器就認識了 define、exports、module 這些東西。也就實現了模塊化。
二、browserify / webpack : 是一個預編譯模塊的方案,相比於上面 ,這個方案更加智能。沒用過browserify,這裏以webpack爲例。首先,它是預編譯的,不須要在瀏覽器中加載解釋器。另外,你在本地直接寫JS,不論是 AMD / CMD / ES6 風格的模塊化,它都能認識,而且編譯成瀏覽器認識的JS。
http://www.ruanyifeng.com/blog/2012/10/javascript_module.html
https://www.jianshu.com/p/5226bd9644b6
http://es6.ruanyifeng.com/#docs/module
原文出處:https://www.cnblogs.com/fozero/p/10328556.html