為了減少變數汙染以及程式碼維護node採用了CommonJS規範。今天模擬一下Module。
- 首先建立被引入檔案 a.js
module.exports = 'hello';
複製程式碼
- 建立Module檔案
//定義Module類
class Module{
constructor(filename){
this.filename = filename;
this.exports = {};
}
}
//定義require方法
function myRequire(){
}
let resut = myRequire('./a');
複製程式碼
- 獲取檔案路徑
function myRequire(filename){
//獲取檔案絕對路徑
filename = Module.getPath(filename);
}
class Module{
...
//Module下定義靜態方法
static getPath(filename){
filename = path.join(__dirname,filename);
let ext = path.extname(filename);
let pathName = '';
let error = filename + " is not exist";
//判斷檔案是否存在擴充名
if(ext){
try{
fs.accessSync(filename);
return filename;
}catch(e){
throw error;
}
}
for(var i=0; i<Module.extentions.length; i++){
//給檔案加上擴充名,查詢檔案是否存在
pathName = filename + Module.extentions[i];
try{
fs.accessSync(pathName);
return pathName;
}catch(e){}
}
throw error;
}
}
//定義擴充名
Module.extentions = ['.js','.json','.node'];
複製程式碼
- 讀取檔案
class Module{
...
load(){
let ext = path.extname(this.filename).slice(1);
//根據檔案型別讀取檔案
Module.extentions[ext](this);
}
static wrap(script){
return Module.warper[0] + script + Module.warper[1];
}
}
Module.extentions["js"] = function(module){
let script = fs.readFileSync(module.filename,'utf8');
let fnStr = Module.wrap(script);
//(function(exports,require,module,__dirname,__filename){module.exports = 'hello'})
let dirname = path.resolve(module.filename,'../');
vm.runInThisContext(fnStr).call(module.exports,module.exports,myRequire,module,dirname,module.filename);
//檔案內部會獲得傳過來的module物件
//模組內部將要匯出的檔案掛載到module.exports上
//module.exports = 'hello'
}
Module.extentions["json"] = function(module){
let script = fs.readFileSync(module.filename,'utf8');
module.exports = JSON.parse(script);
}
//用於拼接巢狀js檔案
Module.warper = ["(function(exports,require,module,__dirname,__filename){", "\n})"];
function myRequire(filename){
...
let module = new Module(filename);
module.load();
}
複製程式碼
- 暫存已讀取檔案
function myRequire(filename){
let fileCache = Module.caches[filename];
//有快取讀取快取
if(fileCache){
return fileCache.exports;
}
//載入檔案
let module = new Module(filename);
module.load();
//快取檔案
Module.caches[filename] = module;
}
複製程式碼
- 完整程式碼
a.js
module.exports = 'hello'
複製程式碼
module.js
let path = require('path');
let fs = require('fs');
let vm = require('vm');
class Module{
constructor(filename){
this.filename = filename;
this.exports = {};
}
load(){
let ext = path.extname(this.filename).slice(1);
Module.extentions[ext](this);
}
static wrap(script){
return Module.warper[0] + script + Module.warper[1];
}
static getPath(filename){
filename = path.join(__dirname,filename);
let ext = path.extname(filename);
let pathName = '';
let error = filename + " is not exist";
if(ext){
try{
fs.accessSync(filename);
return filename;
}catch(e){
throw error;
}
}
for(var i=0; i<Module.extentions.length; i++){
pathName = filename + Module.extentions[i];
try{
fs.accessSync(pathName);
return pathName;
}catch(e){}
}
throw error;
// path.resolve(__dirname, filename);
}
}
Module.extentions = ['.js','.json','.node'];
Module.caches = {};
Module.warper = ["(function(exports,require,module,__dirname,__filename){", "\n})"];
Module.extentions["js"] = function(module){
let script = fs.readFileSync(module.filename,'utf8');
let fnStr = Module.wrap(script);
let dirname = path.resolve(module.filename,'../');
vm.runInThisContext(fnStr).call(module.exports,module.exports,myRequire,module,dirname,module.filename);
}
Module.extentions["json"] = function(module){
let script = fs.readFileSync(module.filename,'utf8');
module.exports = script;
}
function myRequire(filename){
//查詢檔案絕對路徑
filename = Module.getPath(filename);
let fileCache = Module.caches[filename];
if(fileCache){
return fileCache.exports;
}
//載入檔案
let module = new Module(filename);
module.load();
Module.caches[filename] = module;
return module.exports;
}
let school = myRequire('./a.js');
複製程式碼
歡迎大家指出問題提出見解!