先講講模塊加載機(jī)制
require() __filename,__dirname 實(shí)際上不是一個(gè)全部變量,而是每個(gè)模塊內(nèi)部的。
我所講的是當(dāng)前版本6.10的版本,比較穩(wěn)定的
在node.js 模塊和文件是一一對(duì)應(yīng)的损搬,一個(gè)模塊就是一個(gè)文件
__filename是打印出當(dāng)前文件所在的絕對(duì)路徑
__dirname是打印出當(dāng)前文件所在的文件夾目錄
現(xiàn)在比方說在一個(gè)同目錄下叫node文件夾
b.js
let a = "我是b模塊"
console.log(a)
a.js
require("./b.js') //我是b模塊
如果我們?cè)贀Q個(gè)方式想我們既然把b.js模塊加載進(jìn)來了,我們也可以使用b.js里的a 變量
a.js
require("./b.js')
console.log(a) //會(huì)報(bào)一個(gè)錯(cuò)柜与,會(huì)報(bào)a is not defined
這是為什么呢巧勤?
這是因?yàn)槟K加載機(jī)制,模塊看似本地變量的全局變量但是在導(dǎo)入其它模塊中就是一個(gè)私有變量弄匕,在其它模塊是訪問不到的颅悉,除了你export出去等方法
這是因?yàn)樵趫?zhí)行模塊代碼之前,Node.js 會(huì)使用一個(gè)如下的函數(shù)包裝器將其包裝:
(function (exports, require, module, __filename, __dirname) {
// 你的模塊代碼實(shí)際上在這里
});
它保持了頂層的變量(用 var粘茄、const 或 let 定義)作用在模塊范圍內(nèi)签舞,而不是全局對(duì)象。
它有助于提供一些看似全局的但實(shí)際上是模塊特定的變量柒瓣,例如:
實(shí)現(xiàn)者可以使用 module 和 exports 對(duì)象從模塊中導(dǎo)出值。
快捷變量 __filename 和 __dirname 包含模塊的絕對(duì)文件名和目錄路徑吠架。
如果在a模塊導(dǎo)入b模塊的方法
我們可以把所有方法掛在exports對(duì)象上面導(dǎo)入a模塊
b.js
exports.add = (a) => {
console.log(a+1)
}
exports.reduce =(a) => {
console.log(a-1)
}
a.js
const demo = require('./b.js') //用demo這個(gè)變最去接收這個(gè)b.js文件導(dǎo)出來的export對(duì)象
demo.add(1) //2 用點(diǎn)來調(diào)用掛在上面的方法
demo.reduce(1) //0
如果你想導(dǎo)出一整個(gè)對(duì)象或者構(gòu)造函數(shù)芙贫,你可以用module.exports來導(dǎo)出,是用來導(dǎo)出一整個(gè)對(duì)象
b.js
module.exports = (a)=>{
return {
add () {
console.log(a+1)
},
reduce () {
console.log(a-1)
}
}
}
因?yàn)楹瘮?shù)也是對(duì)象傍药,return出去一個(gè)對(duì)象磺平,掛著add 和 reduce方法
a.js
const b = require('./b.js')
var demo = b(1)
demo.add() //2
demo.reduce() //0
訪問主模塊
還是前面的例子
require.main
代表node運(yùn)行的主模塊魂仍,想當(dāng)于module === 主模塊
b.js
console.log(require.main === module)
運(yùn)行node b.js 會(huì)發(fā)現(xiàn) 返回true 因?yàn)閎.js是node運(yùn)行的主模塊
a.js
require(./b.js)
console.log(require.main === module)
運(yùn)行node a.js會(huì)發(fā)現(xiàn) 返回false ,true
因?yàn)榈谝粋€(gè)false是b.js打印出來的,因?yàn)榇藭r(shí)主模塊已經(jīng)變成了a.js
第二個(gè)true 是a.js打印出來的拣挪,因?yàn)榇藭r(shí)主模塊已經(jīng)是a.js了
前面說過每個(gè)文件都是一個(gè)模塊擦酌,也可以看作成一個(gè)對(duì)象,模塊自帶一個(gè)filename屬性菠劝,代表此模塊絕對(duì)路徑存放的地方
b.js
console.log( module.filename)
a.js
require(./b.js)
console.log( module.filename)
運(yùn)行node a.js會(huì)發(fā)現(xiàn) 打印出來赊舶,這個(gè)是我存放文件或者模塊的絕對(duì)路徑
D:\node\b.js
D:\node\a.js
再來看看 require.mian.filename
這個(gè)代表模塊運(yùn)行時(shí)候主模塊的絕對(duì)路徑,什么意思呢赶诊,不大好理解笼平,我給大家演示一下
b.js
console.log(require.main.filename)
如果我先單獨(dú)運(yùn)行node b.js會(huì)發(fā)現(xiàn)
D:\node\b.js 這個(gè)很顯然因?yàn)檫\(yùn)行的主模塊是b.js所以此模塊運(yùn)行時(shí)主模塊的絕對(duì)路徑就是自己
a.js
require(./b.js)
console.log( module.filename)
我們把b.js引入a.js中我們?cè)賜ode a.js運(yùn)行一下看看什么結(jié)果
D:\node\a.js
D:\node\a.js
我們會(huì)發(fā)現(xiàn)無論是 b.js 還是 a.js模塊打印出來的都是 D:\node\a.js 因?yàn)楝F(xiàn)在node主入口運(yùn)行的文件就是a.js所以 他里面所有引入的模塊都是從這個(gè)a.js主模塊的路徑進(jìn)入的,所以b.js主模塊路徑也是D:\node\a.js舔痪,這個(gè)比較煩大家可以去試一下就明白了
模塊加載機(jī)制
- 如果 X 是一個(gè)文件寓调,加載 X 作為 JavaScript 文本。結(jié)束
- 如果 X.js 是一個(gè)文件锄码,加載 X.js 作為 JavaScript 文本夺英。結(jié)束
- 如果 X.json 是一個(gè)文件,解析 X.json 成一個(gè) JavaScript 對(duì)象滋捶。結(jié)束
- 如果 X.node 是一個(gè)文件秋麸,加載 X.node 作為二進(jìn)制插件。結(jié)束
在Node.js中炬太,可以使用require.resolve函數(shù)來查詢某個(gè)模塊文件的帶有完整絕對(duì)路徑的文件名灸蟆,代碼如下所示。
b.js
let b = require.resolve("./b.js")
console.log(b)
運(yùn)行node b.js 會(huì)發(fā)現(xiàn)打印出來此時(shí)./b.js文件的絕對(duì)路徑
D:\node\b.js
注意不會(huì)加載此文件亲族,只是返回此文件的絕對(duì)路徑