path.resolve和path.join是干什么的?

前言

vue 项目配置中经常能见到的 path.resolve() 、path.join()、__dirname,他们到底是个啥?官方的表述是:

__dirname 表示当前模块的目录名(即运行的js文件所在的目录)。

在 Node.js 模块系统中,每个文件都被视为一个独立的模块

path.resolve() 将路径或路径片段的序列解析为绝对路径。
path.join() 将所有给定的 path 片段连接到一起(使用平台特定的分隔符作为定界符),然后规范化生成的路径

嗯,有点抽象。为了更好的弄明白这些,我跑了以下代码 ——


前提条件

以下代码都是基于下面这个目录结构和执行路径的。请注意执行路径! 这是为了区分js文件的所在路径和执行路径,二者的区分有助于更好的理解 resolve 方法。

目录结构:

myTest         
├─ test1       
│  └─ test.js  
└─ test2       

执行路径:E:\myTest\test2


Part1 这几个是啥? 直接输出看看

const path = require('path');
console.log("__dirname ==> ", __dirname)         //返回运行的js文件所在的目录 ==> E:\myTest\test1
console.log("resolve   ==> ", path.resolve(''))  //返回运行时的路径 ==> E:\myTest\test2
console.log("join      ==> ", path.join(''))     //返回.表示当前目录 ==> .

Part2 接下来再对比一下 resolve 和 join

const path = require('path');
console.log("resolve   ==> ", path.resolve('a/b','c','d')) // E:\myTest\test2\a\b\c\d 
console.log("join      ==> ", path.join('a/b','c','d'))    // a\b\c\d
//从二者的结果中可以看到, 路径被规范化了 (不同系统的路径符号不同,可能是 \  也可能是 /)

Part3 再加点料
基于 Part2 的代码,给路径片段 d 分别加上 /./../ 试试

console.log("使用 /") 
console.log("resolve   ==> ", path.resolve('a/b','c','/d'))  // E:\d
console.log("join      ==> ", path.join('a/b','c','/d'))     // a\b\c\d

console.log("使用 ./") 
console.log("resolve   ==> ", path.resolve('a/b','c','./d')) // E:\myTest\test2\a\b\c\d
console.log("join      ==> ", path.join('a/b','c','./d'))    // a\b\c\d

console.log("使用 ../") 
console.log("resolve   ==> ", path.resolve('a/b','c','../d')) // E:\myTest\test2\a\b\d
console.log("join      ==> ", path.join('a/b','c','../d'))    // a\b\d

包含以 /./../ 开头的路径片段,分别代表:根目录(/), 当前目录(./), 上级目录(…/)。用法同命令行中使用 cd 啥啥啥

Part4 搭配 __dirname 食用
再基于 Part3 ,加上 __dirname 作为第一个参数(这个有点意思,注意看看与上例的区别)

console.log("使用 /") 
console.log("resolve   ==> ", path.resolve(__dirname, 'a/b','c','/d')) // E:\d
console.log("join      ==> ", path.join(__dirname, 'a/b','c','/d'))    // E:\myTest\test1\a\b\c\d

console.log("使用 ./") 
console.log("resolve   ==> ", path.resolve(__dirname, 'a/b','c','./d')) // E:\myTest\test1\a\b\c\d
console.log("join      ==> ", path.join(__dirname, 'a/b','c','./d'))    // E:\myTest\test1\a\b\c\d

console.log("使用 ../") 
console.log("resolve   ==> ", path.resolve(__dirname, 'a/b','c','../d')) // E:\myTest\test1\a\b\d
console.log("join      ==> ", path.join(__dirname, 'a/b','c','../d'))    // E:\myTest\test1\a\b\d

Part 5 加个带盘符的路径片段试试
同样基于 Part3 ,这次不加 __dirname , 加个带盘符的路径片段(效果似乎跟加__dirname 一样)

console.log("使用 /") 
console.log("resolve   ==> ", path.resolve('F:/', 'a/b','c','/d')) // F:\d
console.log("join      ==> ", path.join('F:/', 'a/b','c','/d'))    // F:\a\b\c\d

console.log("使用 ./") 
console.log("resolve   ==> ", path.resolve('F:/', 'a/b','c','./d')) // F:\a\b\c\d
console.log("join      ==> ", path.join('F:/', 'a/b','c','./d'))    // F:\a\b\c\d

console.log("使用 ../") 
console.log("resolve   ==> ", path.resolve('F:/', 'a/b','c','../d')) // F:\a\b\d
console.log("join      ==> ", path.join('F:/', 'a/b','c','../d'))    // F:\a\b\d

OK,从以上的运行结果,可以看出点端倪来了:
path.resolve 基于运行时的路径,返回拼接后的绝对路径。但如果路径片段中包含带盘符,则以该盘符为准。

emm… 好像有点毛病,如果同时使用了__dirname和带盘符的路径片段呢?或者不是作为首位参数
我再跑一个试试……

Part6 同时使用__dirname和带盘符的路径片段 & 不是作为首位参数的情况

console.log("resolve   ==> ", path.resolve(__dirname, 'F:/', 'a/b','c'))		// F:\a\b\c
console.log("resolve   ==> ", path.resolve('F:/', __dirname, 'a/b','c'))		// E:\myTest\test1\a\b\c
console.log("resolve   ==> ", path.resolve('x/y', 'F:/', __dirname, 'a/b','c'))	// E:\myTest\test1\a\b\c

好的,我知道了。换个更准确的表述:

path.resolve
路径片段从右到左依次拼接,直至返回完整的绝对路径。如果传入的路径片段中没有带盘符的,就拿运行时的路径来用啦~

path.join

路径片段从右到左依次拼接,返回拼接好的路径片段


总结

二者的共同点:

  • 路径都会被规范化
  • 都是从右到左拼接路径片段

二者的不同点:

  • resolve 返回绝对路径,join 只把路径片段拼接
  • / 符号在 resolve 中表示根目录,在 join 中没有这个效果

附上完整的测试代码,可以跑一下看看~
const path = require('path');

// 这几个是啥? 直接输出看看
console.log("----------------------------------") 
console.log("__dirname ==> ", __dirname)         //返回运行的js文件所在的目录 ==> E:\myTest\test1
console.log("resolve   ==> ", path.resolve(''))  //返回运行时的路径 ==> E:\myTest\test2
console.log("join      ==> ", path.join(''))     //返回.表示当前目录 ==> .
console.log("----------------------------------") 

// 接下来再对比一下 resolve 和 join
console.log("resolve   ==> ", path.resolve('a/b','c','d')) // E:\myTest\test2\a\b\c\d 
console.log("join      ==> ", path.join('a/b','c','d'))    // a\b\c\d
// 从二者的结果中都可以看到, 路径被规范化了 (不同系统的路径符号不同,可能是 \  也可能是 /)
console.log("----------------------------------")          

// 再加点料 ----
// 路径片段以 /  ./  ../ 开头,分别代表:根目录(/), 当前目录(./), 上级目录(../)
// 用法同命令行中使用 cd **
console.log("============ 基础使用 ============") 
console.log("使用 /:") 
console.log("resolve   ==> ", path.resolve('a/b','c','/d'))  // E:\d
console.log("join      ==> ", path.join('a/b','c','/d'))     // a\b\c\d
console.log("----------------------------------") 
console.log("使用 ./:") 
console.log("resolve   ==> ", path.resolve('a/b','c','./d')) // E:\myTest\test2\a\b\c\d
console.log("join      ==> ", path.join('a/b','c','./d'))    // a\b\c\d
console.log("----------------------------------") 
console.log("使用 ../:") 
console.log("resolve   ==> ", path.resolve('a/b','c','../d')) // E:\myTest\test2\a\b\d
console.log("join      ==> ", path.join('a/b','c','../d'))    // a\b\d
console.log("==================================") 

// 加上 __dirname 的使用
console.log("========= 加上 __dirname =========") 
console.log("使用 /:") 
console.log("resolve   ==> ", path.resolve(__dirname, 'a/b','c','/d')) // E:\d
console.log("join      ==> ", path.join(__dirname, 'a/b','c','/d'))    // E:\myTest\test1\a\b\c\d
console.log("----------------------------------") 
console.log("使用 ./:") 
console.log("resolve   ==> ", path.resolve(__dirname, 'a/b','c','./d')) // E:\myTest\test1\a\b\c\d
console.log("join      ==> ", path.join(__dirname, 'a/b','c','./d'))    // E:\myTest\test1\a\b\c\d
console.log("----------------------------------") 
console.log("使用 ../:") 
console.log("resolve   ==> ", path.resolve(__dirname, 'a/b','c','../d')) // E:\myTest\test1\a\b\d
console.log("join      ==> ", path.join(__dirname, 'a/b','c','../d'))    // E:\myTest\test1\a\b\d
console.log("----------------------------------") 

// 不要 __dirname , 但是加个带盘符的路径片段 ==> 效果跟加是 __dirname 一样
console.log("========== 加个带盘符的 ==========") 
console.log("使用 /:") 
console.log("resolve   ==> ", path.resolve('F:/', 'a/b','c','/d')) // F:\d
console.log("join      ==> ", path.join('F:/', 'a/b','c','/d'))    // F:\a\b\c\d
console.log("----------------------------------") 
console.log("使用 ./:") 
console.log("resolve   ==> ", path.resolve('F:/', 'a/b','c','./d')) // F:\a\b\c\d
console.log("join      ==> ", path.join('F:/', 'a/b','c','./d'))    // F:\a\b\c\d
console.log("----------------------------------") 
console.log("使用 ../:") 
console.log("resolve   ==> ", path.resolve('F:/', 'a/b','c','../d')) // F:\a\b\d
console.log("join      ==> ", path.join('F:/', 'a/b','c','../d'))    // F:\a\b\d
console.log("----------------------------------") 

// 同时使用了 __dirname和盘符,或者穿插在其他路径片段里面
console.log("========== 这是要搞事情啊 ==========") 
console.log("resolve   ==> ", path.resolve(__dirname, 'F:/', 'a/b','c'))		//F:\a\b\c
console.log("resolve   ==> ", path.resolve('F:/', __dirname, 'a/b','c'))		//E:\myTest\test1\a\b\c
console.log("resolve   ==> ", path.resolve('x/y', 'F:/', __dirname, 'a/b','c'))	//E:\myTest\test1\a\b\c

你可能感兴趣的:(Node,nodejs)