前言
一直感覺模組化是一個很神祕的概念,因而也很感興趣,有幸瞭解到了模組化的歷史,嘗試著瞭解了一下模組化的實現,發現了一個很有意思的東西,不知道為什麼,會覺得很有成就感,記錄一下。
模組化的實現
簡單模擬一下CMD的module實現,在module.js中做以下處理
//module.js
exports.word = 'hello'
module.exports = function () {
console.log(exports.word)
}
複製程式碼
然後在test.js介面引入該模組
//test.js
const file = require('./module.js')
file() // hello
console.log(file.word) //undefined
複製程式碼
不考慮為什麼會有這樣的結果,上面的這部分是通過require引用模組的常見寫法。下面的超簡化版本程式碼實現了超簡化的require方法(下面的runner方法)
//require.js
const fs = require('fs')
const path = require('path')
function runner(file) {
const code = fs.readFileSync(path.join(__dirname, file), 'utf-8')
const module = { exports: {} }
const fn = new Function('module', 'exports', code)
fn(module, module.exports)
return module.exports
}
複製程式碼
這裡的fn整理出來就是下面這一段程式碼
function _fn(module, exports) {
exports.word = 'hello'
module.exports = function() {
console.log(exports.word)
}
}
複製程式碼
所以在執行fn(module, module.exports)
時,就是對上面宣告的const module = { exports: {} }
進行賦值。當執行runner方法時,其實就是獲取module.exports
的值。而runner方法做的事,就是獲取檔案中的內容,識別module.exports
,並把該值丟擲來。轉到require,其實主要做的也就是這部分工作。module和 export也就成了關鍵詞,用來在讀取模組的時候識別的標識。
runner方法已經實現了,現在來看一下為什麼執行後是這樣的結果。
export 與 module.export
通過上面runner
的實現,也可以看出,其實exports
和module.exports
最後被引用後其實是一個。最後暴露出來的都是module
物件,而如果一個頁面中同時存在exports
和module.exports
,最後一個引用都會覆蓋掉掉前面所有的exports
引用,所以這也是為什麼上面的file()
能執行成功,而file.word
為undefined
,因為前者覆蓋了後者。file
已經被替換成了下面這個方法
function() {
console.log(exports.word)
}
複製程式碼
模組化
那麼什麼叫模組化呢?我的理解有3點:
- 引用的時候能按需呼叫
- 外部呼叫無法修改內部引數
- 沒有全域性變數的汙染,方法名不衝突
因為看了模組化的歷史,瞭解到模組化最最原始是從匿名閉包衍生出來的,再看看現在的module的實現,其實也是一個閉包。雖然之前看了很多閉包的概念,但因為使用上的侷限性,一直把閉包誤解為只有return出去的才是閉包。比如下面這段程式碼
function fo(){
var a = 'aaa';
return function(){
console.log(a)
}
}
var bar = fo();
複製程式碼
這次看到這個是真的有重新整理我的認知,原來下面這樣的也是閉包
var b = {
a: {}
}
function fo(obj){
let a = 'aaa';
obj.a = function(){
console.log(a)
}
}
fo(b.a);
複製程式碼
把上面這個再擴充套件一下就成了下面這段程式碼,一段類似_fn的程式碼
var b = {
a: {}
}
function fo(b, a){
a = '111';
b.a = function(){
console.log(a)
}
}
fo(b, b.a);
複製程式碼
重複一波閉包的概念:能夠讀取其他函式內部變數的函式。
所以這也是為什麼上面的file()
的結果是hello
,這也是requireJS的模組化裡面我暫時接觸到的最有意思的地方。下次瞅一瞅es6的模組化
相關知識
模組化的歷史:huangxuan.me/js-module-7…