path.resolve 與 path.join 的區(qū)別詳解

配圖源自 Freepik

前言

相信大家一定用過(guò) path.resolve()path.join(),特別是 Webpack、Rollup、Vite 等構(gòu)建工具,再熟悉不過(guò)了。

path.resolve(__dirname, 'src/index.js')

像這個(gè)例子,用 path.join(__dirname, 'src/index.js') 所得到的結(jié)果也是完全一樣的。
那么它倆究竟有何不同,在什么情況下使用才能體現(xiàn)出區(qū)別呢?

path.resolve

該函數(shù)接受「零或多個(gè)」字符串類型的路徑參數(shù),并返回一個(gè) normalized 的「絕對(duì)路徑」。

path.resolve(path1, path2, ..., pathN)

有以下幾個(gè)特點(diǎn):

  • 其中 zero-length 的參數(shù)會(huì)被忽略,比如 ''(空字符串)和 '.'(表示當(dāng)前目錄)。
  • / 開(kāi)頭的參數(shù)會(huì)被當(dāng)作文件系統(tǒng)根路徑,不以 .././ 開(kāi)頭的參數(shù)會(huì)被當(dāng)作是目錄。
  • 若參數(shù)不為字符串類型,則會(huì)拋出 TypeError。
  • 若不傳遞任何參數(shù)時(shí),返回 Node 進(jìn)程的當(dāng)前工作目錄。因此 path.resolve() === process.cwd() 結(jié)果為 true
  • 結(jié)果返回之前其內(nèi)部也會(huì)做類似 path.normalize() 的路徑規(guī)范化處理。

看例子:

path.resolve('/a', 'b', 'c') // return: "/a/b/c"
path.resolve('/a', '/b', 'c') // return: "/b/c"
path.resolve('/a', '/b', '/c') // return: "/c"

其實(shí)在官網(wǎng)就描述得很清晰了。無(wú)非就是,「從右到左」一個(gè)一個(gè)參數(shù)開(kāi)始解析,每解析一個(gè)就將其加到原來(lái)路徑的「前面」,參數(shù)之間使用平臺(tái)對(duì)應(yīng)的路徑分隔符連接。若能拼接成一個(gè)絕對(duì)路徑,就停止解析并立即返回。如果將所有參數(shù)都解析完,仍然無(wú)法拼湊得出一個(gè)絕對(duì)路徑,那么就講這些參數(shù)的結(jié)果拼到當(dāng)前工作目錄中,以得出絕對(duì)路徑。

因此,上述示例內(nèi)部解析過(guò)程如下:

"c" -> "b/c" -> "/a/b/c"
"c" -> "/b/c"
"/c"

假設(shè)有 path.resolve('a', 'b'),就是 "b" -> "a/b" -> "process.cwd()/a/b" 的過(guò)程,相當(dāng)于 path.resolve(process.cwd(), 'a', 'b')。其中 proccess.cwd() 就是當(dāng)前工作目錄。

個(gè)人認(rèn)為,更好的理解倒是「從左往右」看,將 path.resolve() 方法看作 Shell 的 cd 操作,只是前者不管文件系統(tǒng)是否存在此目錄或文件。如偽代碼:

path.resolve('/a', '/b', 'c')

// 相當(dāng)于
$ cd /a; cd /b; cd c

或許 path.resolve() 稱為 path.cd() 更讓人豁然開(kāi)朗吧。

path.join

該函數(shù)接受「零或多個(gè)」字符串類型的路徑參數(shù),返回一個(gè)所有參數(shù)拼接起來(lái)的(相對(duì)/絕對(duì))路徑。

path.join(path1, path2, ..., pathN)

有以下幾個(gè)特點(diǎn):

  • 其中 zero-length 的參數(shù)會(huì)被忽略,比如 ''(空字符串)和 '.'(表示當(dāng)前目錄)。
  • ../ 開(kāi)頭的參數(shù)認(rèn)為是上一級(jí)目錄。
  • 第一個(gè)參數(shù)若以 / 會(huì)被認(rèn)為是根目錄,其他以 / 開(kāi)頭的參數(shù)作用與 ./ 相同。
  • 若參數(shù)不為字符串類型,則會(huì)拋出 TypeError。
  • 若不傳遞任何參數(shù)時(shí),返回 .(當(dāng)前目錄)。
  • 結(jié)果返回之前其內(nèi)部也會(huì)做類似 path.normalize() 的路徑規(guī)范化處理。

看例子:

path.join('a', 'b', 'c') // return: "a/b/c"
path.join('/a', 'b', 'c') // return: "/a/b/c"
path.join('/a', '/b', 'c') // return: "/a/b/c"
path.join('/a', '/b', '/c') // return: "/a/b/c"

其實(shí)不用看那么多,換個(gè)角度去理解或許更清晰,兩個(gè)步驟:

  1. 用相加運(yùn)算符 + 將所有參數(shù)連接起來(lái)(參數(shù)之間用 / 連接)。
  2. 使用 path.normalize() 對(duì)相加后的字符串路徑作規(guī)范化處理。

有人可能會(huì)問(wèn),path.normalize() 又是干嘛的啊。很簡(jiǎn)單:把 ./、../ 翻譯成對(duì)應(yīng)路徑;把多余無(wú)用的路徑連接符干掉(如 a//b => a/b);將路徑連接符轉(zhuǎn)換為特定平臺(tái)的連接符(比如 Unix 的 /,Windows 的 \)。

因此,可以把 path.join('/a', '/b', 'c') 理解成這樣:

let args = ['/a', '/b', 'c']
let str = args.join('/') // "/a//b/c"
str = path.normalize(str) // "/a/b/c"

區(qū)別

以幾個(gè)示例做總結(jié):

無(wú)參數(shù)時(shí)

path.resolve() // 返回當(dāng)前工作目錄,相當(dāng)于 `process.cwd()`,是絕對(duì)路徑。
path.join() // 返回 `.`(當(dāng)前目錄),是相對(duì)路徑。

?? 請(qǐng)注意「當(dāng)前工作目錄」和「當(dāng)前目錄」的區(qū)別。

有多個(gè)參數(shù),且中間參數(shù)以 / 開(kāi)頭

path.resolve('/a', '/b', 'c') // 返回 `/b/c`,絕對(duì)路徑。
path.join('/a', '/b', 'c') // 返回 `/a/b/c`,絕對(duì)路徑。
path.resolve('a', '/b', 'c') // 返回 `/b/c`,絕對(duì)路徑。
path.join('a', '/b', 'c') // 返回 `a/b/c`,相對(duì)路徑。

相信大家都懂了。

The end.

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

相關(guān)閱讀更多精彩內(nèi)容

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