commanjs中導(dǎo)入模塊require('./')的原理

一、原理

module、exports、require都不存在在全局上,那么為什么模塊可以使用這些變量。
分析require的原理

//require中的偽代碼
function require(moudlePath) {
    //1.根據(jù)傳遞的模塊路徑,得到完整的絕對路徑
    var moudleId = require.resolve(moudlePath)
    //2.判斷緩存
    if(cache[moduleId]) {
        return cache[moudleId]
    }
    //3.真正運(yùn)行模塊代碼的輔助函數(shù)
    function _require(exports, require, module, _filename, _dirname) {
        //目標(biāo)模塊的代碼在這里執(zhí)行
    }
    
    //4.準(zhǔn)備并運(yùn)行輔助函數(shù)
    var module = {
        exports: {}
    };
    var exports = module.exports;
    var _filename = moudleId; //得到模塊文件的絕對路徑
    var _dirname = ...; //得到模塊所在目錄的絕對路徑
    _require.call(exports, exports, _require, module, _filename, _dirname)
    //5.緩存module.exports
    cache[moduleId] = module.exports;
    //6. 返回module.exports;
    return module.exports
}

1.通過resolve()將傳入的模塊路徑moudlePath轉(zhuǎn)化成絕對路徑,保證路徑的唯一性;
2.通過cache緩存表查看是否有moudleId對應(yīng)的屬性值,若有就返回屬性值,避免多次執(zhí)行。

//cache就是一個(gè)對象
cache {
  moudleId: XXX
}

3.目標(biāo)模塊的代碼就是在_require()中執(zhí)行的,這也就是模塊間不會(huì)造成全局變量污染的真正原因,_require()有五個(gè)參數(shù),exports, require, module, _filname, _dirname
4.module是一個(gè)對象,exports是module對象中一個(gè)屬性,屬性值也是一個(gè)對象,_filename是moduleId代表的絕對路徑,_dirname是模塊所在目錄的絕對路徑。執(zhí)行_require()利用call將_require()的this指向了exports。所以,這時(shí)的this === exports === module.exports。
5.將module.exports和對應(yīng)的moduleId添加到緩存表cache中
6.返回module.exports,所以require('./')導(dǎo)入的是目標(biāo)模塊的module.exports

二、面試題

// a.js
exports.a = 1;
module.exports.b = 2;
module.exports = function(){}
module.exports.c = 3;
exports.d = 4;
this.e = 5;
console(this === exports);
console(this === module.exports);
console(exports === module.exports);

// index.js
var a = arguments[1]("./a.js")
console.log(typeof a);
console.log(a.a, a.b, a.c, a.d, a.e);
console.log(arguments.length);

首先看index.js
var a = arguments[1]("./a.js")
arguments[1]對應(yīng)的是5個(gè)參數(shù)中的第二個(gè)參數(shù)require,所以其實(shí)就是var a = require("./a.js")
導(dǎo)入模塊后,就將模塊路徑轉(zhuǎn)成絕對路徑,并檢查緩存,然后在_require()執(zhí)行目標(biāo)模塊a.js的代碼
a.js運(yùn)行過程:

最初 this === exports === module.exports
1.exports.a = 1;
exports {
    a: 1
}
2.module.exports.b = 2;
exports { //module.exports == exports
    a: 1,
    b: 2
}
3.module.exports = function() {}
這時(shí)三者關(guān)系改變,module.exports脫離組織
this == exports     module.exports = function(){}
4.module.exports.c = 3 
本質(zhì)上來說function(){}也是一個(gè)對象
module.exports {
  c: 3
}
5.exports.d = 4
exports {
    a: 1,
    b: 2,
    d: 4
}
6.this.e = 5
exports {
    a: 1,
    b: 2,
    d: 4,
    e: 5
}
7.console(this === exports)
true
8.console.log(this === module.exports)
false
9.console.log(exports === module.exports)
false
a.js執(zhí)行完成

1.console.log(typeof(a))
a接收的是require("./a.js")返回的結(jié)果,所a的類型就module.exports的類型,所以typeof(a) 為function
2.console.log(a.a, a.b, a.c, a.d, a.e)
module.exports=function() {c=3}
也就是
module.exports: {
  c: 3
}
所以對應(yīng)結(jié)果為undefined,undefined,3,undefined,undefined
3.console.log(arguments.length)
arguments有5個(gè)參數(shù) exports,require,module,_filename,_dirname
arguments.length == 5

最終結(jié)果:
true
false
false
function
undefined undefined 3 undefined undefined 
5
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容