明白 JS 模組化

yck發表於2017-08-29

模組化是什麼,有什麼用?

模組化就是將一個大的功能拆分為多個塊,每一個塊都是獨立的,你不需要去擔心汙染全域性變數,命名衝突什麼的。

那麼模組化的好處也就顯然易見了

  • 解決命名衝突
  • 依賴管理
  • 程式碼更加可讀
  • 提高複用性

早期苦逼的前端er

但是,JS 這門語言在最初是沒有這個設計的。所以也就苦了早期的前端開發者。下面介紹下最開始的寫法。

函式封裝

這個嘛,誰都會,最大的缺點就是汙染全域性作用域了

function fn1() {
    // balabalabala
}
function fn2() {
    // balabalabala
}複製程式碼

物件

這個嘛,也是誰都會的,最大的缺點就是沒有私有變數,外部能改

var myModule = {
    var1: 1,
    fn1: function() {}
}複製程式碼

立即執行函式

這個嘛,高階了點,並且也有了模組化的意思,這種寫法在老專案中很常見,一個 JS 檔案中就是一個立即執行函式

(function(){
   // ....
})()複製程式碼

CommonJS

瀏覽器這邊表示沒有模組化還行,就是寫邏輯麻煩了點。但是搞服務端的必須得有這玩意啊,所以 Node.js 第一個搞出了 CommonJS規範

// a.js
module.exports = {
    a: 1
}
// or 
exports.a = 1

// b.js
var module = require('./a.js')
module.a // -> log 1複製程式碼

上面的寫法很好用,但是 module.exportsexports 是咋回事?為啥這幾句程式碼就實現模組化了,讓我們來看一下基礎的實現

先說 require

var module = require('./a.js')
module.a 
// 這裡其實就是包裝了一層立即執行函式,這樣就不會汙染全域性變數了,
// 重要的是 module 這裡,module 是 Node 獨有的一個變數
module.exports = {
    a: 1
}
// 基本實現
var module = {
  id: 'xxxx', // 我總得知道怎麼去找到他吧
  exports: {} // exports 就是個空物件
}
// 這個是為什麼 exports 和 module.exports 用法相似的原因
var exports = module.exports 
var load = function (module) {
    // 匯出的東西
    var a = 1
    module.exports = a
    return module.exports
};
// 然後當我 require 的時候去找到獨特的
// id,然後將要使用的東西用立即執行函式包裝下,over複製程式碼

再來說說 module.exportsexports,用法其實基本是相似的,但是不能對 exports直接賦值,不會有任何效果,看了上面程式碼的同學肯定明白為什麼了。

CommonJS規範是 Node 獨有的,瀏覽器中使用就需要用到 Browserify 解析了,所以後面又蹦出了兩個規範。

AMD && CMD

AMD 是由 RequireJS 提出的,CMD 由 SeaJS 提出。兩者用法基本相似,當然現在用的人應該也不多了,瞭解下語法,看專案的時候不至於懵逼就行

// AMD
define(['./a', './b'], function(a, b) { 
    a.do()
    b.do()
}) 
define(function(require, exports, module) {   
var a = require('./a')  
a.doSomething()   
var b = require('./b') 
b.doSomething() 
})複製程式碼

原生登場

ES6總算原生支援模組化了,譭譽參半吧。當然這個語法還是早支援早好。

// 引入的語法就這樣 import,XXX 這裡有很多語法變化
import XXX from './a.js'
// 匯出也有很多語法變化的寫法,基本的就這兩個,反正語法沒什麼難得
export function a() {}
export default function() {}複製程式碼

最後

這裡基本的介紹了下模組的幾種寫法,如有錯誤,請提出,謝謝!

答疑

評論裡有問到為什麼直接對 exports 賦值無效。首先 require 出來的是 module.exports 物件,然後看下面的程式碼

var a = {}
a.exports = {}
// 把 e 看成 exports,現在 e === a.exports
var e = a.exports
// 引用的關係,同時也修改了 a.exports
e.c = 1
console.log(a.exports.c) // -> 1

// 但是當給 e 賦值的話就等於修改了引用了, 所以並沒有修改 a.exports
e = xxxx複製程式碼

相關文章