一、原理
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