模塊化開發(一)

什麼是模塊化

將一組模塊(及其依賴項)以正確的順序拼接到一個文件(或一組文件)中的過程。javascript

傳統的模塊化作法。

模塊是實現特定功能的一組屬性和方法的封裝。html

將模塊寫成一個對象,全部的模塊成員都放到這個對象裏面。java

var module1 = new Object({
  _count:0,
  f1:function(){},
  f2:function(){}
})
module1.f1()
module1.f2()

上面的對象能夠改變裏面的屬性和方法,不安全git

var module1 = (function(){
 var count=0;
 return { 
   f1:function(){},
  f2:function(){}}
}());
module1.f1()
module1.f2()
module1.count //undefined

使用 將相應的方法和屬性封裝在函數中,這樣就不會暴露私有成員es6

利用構造函數封裝對象

function Father (){
  var arr =[];
  this.add = function (val){
       arr.push(val)
  }
  this.toString = function(){
    return arr.join('');
  }
}
var a = new Father();
a.add(1);//[1]
a.toString();//"1"
a.arr // undefined

上面的函數將 arr 變成私有變量,在函數外部沒法訪問,可是造成了閉包,很是耗費內存;
違背了構造函數與實例對象在數據上相分離的原則(即實例對象的數據,不該該保存在實例對象之外)。github

function ToString() {
  this._buffer = [];
}

ToString.prototype = {
  constructor: ToString,
  add: function (str) {
    this._buffer.push(str);
  },
  toString: function () {
    return this._buffer.join('');
  }
};

雖然上面的構造函數未生成閉包,可是外部能夠修改方法和屬性,不安全數組

放大模式

若是一個模塊很大或者一個模塊須要繼承另外一個模塊能夠利用當即執行函數的特效來封裝瀏覽器

var module1 = (function(m1){
mod1.col=function(){
  console.log(this)
};
return mod1;
}(window.modlue2 ||{})) //有些模塊多是null 確保函數正常執行 採用兼容模式 window.modlue2 ||{}
  • 獨立性是模塊的重要特色,模塊內部最好不與程序的其餘部分直接交互。
var module1 = (function ($, Swiper) {
 //...
}(jQuery, Swiper));

上面的 module1 引入 jQuery 和 Swiper 當作兩個參數傳入模塊中,保證了模塊的獨立性,還使得模塊之間的依賴關係變得明顯。緩存

當即執行函數還能夠起到命名空間的做用。安全

(function($, window, document) {

  function go(num) {
  }

  function handleEvents() {
  }

  function initialize() {
  }

  function dieCarouselDie() {
  }

  //attach to the global scope
  window.finalCarousel = {
    init : initialize,
    destroy : dieCarouselDie
  }

}( jQuery, window, document ));

以上都有一個共同點:使用單個全局變量箭頭代碼包裝在函數中,使用閉包創建私有空間
可是都有缺點:

  • 不知道模塊(庫) 的加載順序
  • 仍是有可能引發命名衝突,好比兩個庫都有相同的名稱,或者使用哪一個版本
    有幾種良好實施的方法:CommonJS、AMD和CMD。能夠解決以上的缺陷

CommonJS

  • CommonJS 是一種思想, 本質上是可複用的JavaScript,它導出特定的對象,提供其它程序使用。

  • 因爲 JavaScript 沒有模塊系統、標準庫較少、缺少包管理工具,所以CommonJS是爲它的表現來制定規範。

  • 每一個JavaScript 文件 都將模塊存儲在本身獨有的做用域中。

  • 須要使用 module.exportsexports.obj 來導出對象,並在須要它的程序中使用 require('module') 加載

//文件1
function myModule() {
 this.hello = function() {
   return 'hello!';
 }

 this.goodbye = function() {
   return 'goodbye!';
 }
}

module.exports = myModule;


//文件2
var myModule = require('myModule');

var myModuleInstance = new myModule();
myModuleInstance.hello(); // 'hello!'
myModuleInstance.goodbye(); // 'goodbye!'

實現原理

var module1 = { 
   export1:{}
 };

 (function (module,exports){
    exports.add = functon(val){
       return val *10
    }
 }(module1,module1.export1));

 var fn = module1.export1.add;
 fn(2)//20

利用當即執行函數 接受兩個參數 module 和 exports, 模塊就經過當即執行函數賦值,而後導出模塊,便可實現模塊的加載
這種方法的好處:

  • 避免全局污染
  • 明確依賴項目
  • 語法清晰
    缺點:
  • 因爲 CommonJS 採用服務器優先方法而且同步加載模塊,所以在瀏覽器中使用它會阻止瀏覽器運行其餘內容,直到加載完成。

咱們可使用 AMD 來異步加載

AMD(Asynchromous Module Definition)

  • 定義了一套 JavaScript 模塊依賴異步加載標準,來解決同步加載的問題。
  • AMD模塊加載不影響後面語句的運行。全部依賴某些模塊的語句均放置在回調函數中。
  • 定義了一個函數 define,經過 define 方法定義模塊。
define(['myModule', 'myOtherModule'], function(myModule, myOtherModule) {
 console.log(myModule.hello());

});

上面的 define 函數將每一個模塊的依賴項,以數組的形式做爲參數。

這些依賴項會在後臺異步加載,一旦加載完成,define 函數就調用模塊給出的回調函數
myModule 可能像下面同樣定義:

define([], function() {

  return {
    hello: function() {
      console.log('hello');
    },
    goodbye: function() {
      console.log('goodbye');
    }
  };
});

CMD(Common Module Definition)

  • CMD由玉伯大佬提出並用於SeaJS
  • CMD 和 AMD 很類似,都有 define 函數, 經過 require 加載

CMD和AMD 不一樣點:

  • 對於依賴的模塊 CMD 延遲執行, AMD 提早執行(requireJS 高版本也開始延遲執行)
  • CMD使用依賴就近原則(按需加載):
define(function(require, exports, module) {   
         var near = require('./a')   
         near.doSomething()   
         // 此處略去 100 行  
          var nearOne = require('./b') // 依賴能夠就近書寫   
          nearOne.doSomething()   // ...
           })
  • AMD使用依賴前置原則(必須先加載完依賴):
define(['./a', './b'], function(nearTow, nearThree) { // 必須一開始加載
           nearTow.doSomething()
           // 此處略去 100 行
           nearThree.doSomething()
           ...
           })
  • CMD 裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每一個 API 都簡單純粹。 AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。好比 AMD 裏,require 分全局 require 和局部 require,都叫 require。

AMDCommonJS 不一樣點:

AMD

  • 採用瀏覽器優先的方法,異步加載,主要用於瀏覽器
  • 先加載依賴項
  • 依賴項能夠說 對象、函數、構造函數、字符串等等其餘JS類型

CommonJS:

  • 採用服務器優先的方法,同步加載,主要用於服務器
  • 支持對象做爲模塊
    共同點: 先加載依賴項

通用模塊定義 UMD

同時支持 AMDCommonJS
本質 建立了一種方法來使用二者的任何一種,同時支持全局變量定義,(JS兼容性的經常使用思想)因此 UMD 能夠在客戶端和服務器上工做

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
      // AMD
    define(['myModule', 'myOtherModule'], factory);
  } else if (typeof exports === 'object') {
      // CommonJS
    module.exports = factory(require('myModule'),
     require('myOtherModule'));
  } else { 
    root.returnExports = factory(root.myModule, root.myOtherModule);
  }
}(this, function (myModule, myOtherModule) {
  function notHelloOrGoodbye(){}; 
  function hello(){}; 
  function goodbye(){}; 
  return {
      hello: hello,
      goodbye: goodbye
  }
}));

ES6模塊(即 ES2015/ECMAScript 六、ES6

  • 使用 import 關鍵字引入模塊,經過 export 關鍵字導出模塊
  • ES6目前沒法在瀏覽器中執行,只能經過babel將不被支持的import編譯爲當前受到普遍支持的 require。
//a.js
export let cun =1; 
export function add() {
  cun++;
}
//----------------
import { cun, add } from './a.js';
console.log(cun); // 1
incCounter();
console.log(cun); // 2
export var fo ='a';
setTimeout(() => fo ='b',500);

import {fo} from './a.js';
console.log(fo);//'a'
setTimeout(()=> console.log(fo),500)//'b'

//ES6 輸入的模塊變量,只是一個「符號鏈接」,因此這個變量是隻讀的,對它進行從新賦值會報錯。
fo = 's' //error
  • ES6 模塊之中,頂層的this指向undefined,即不該該在頂層代碼使用this。
    CommonJSAMDCMD相比:
  • ES6模塊是動態引用,而且不會緩存值,模塊裏面的變量綁定其所在的模塊。
  • ES6 對外接口只是一種靜態定義,在代碼靜態解析階段就會生成。
  • ES6 module編譯時輸出接口(加載),輸出的是值的引用。(靜態編譯)
  • CommonJS 加載的是一個對象(即module.exports屬性),該對象只有在腳本運行完纔會生成。
  • CommonJS 模塊運行時加載,輸出的是一個值的拷貝。(動態編譯)
    一旦輸出一個值,模塊內部的變化就影響不到這個值。
// lib/counter.js

var counter = 1;

function increment() {
  counter++;
}

function decrement() {
  counter--;
}

module.exports = {
  counter: counter,
  increment: increment,
  decrement: decrement
};


// src/main.js

var counter = require('../../lib/counter');

counter.increment();
console.log(counter.counter); // 1

模塊化開發(二)

相關文章
相關標籤/搜索