模組化是什麼,有什麼用?
模組化就是將一個大的功能拆分為多個塊,每一個塊都是獨立的,你不需要去擔心汙染全域性變數,命名衝突什麼的。
那麼模組化的好處也就顯然易見了
- 解決命名衝突
- 依賴管理
- 程式碼更加可讀
- 提高複用性
早期苦逼的前端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.exports
和 exports
是咋回事?為啥這幾句程式碼就實現模組化了,讓我們來看一下基礎的實現
先說 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.exports
和 exports
,用法其實基本是相似的,但是不能對 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複製程式碼