
前言
相信大家一定用过 path.resolve() 或 path.join(),特别是 Webpack、Rollup、Vite 等构建工具,再熟悉不过了。
path.resolve(__dirname, 'src/index.js')
像这个例子,用 path.join(__dirname, 'src/index.js') 所得到的结果也是完全一样的。
那么它俩究竟有何不同,在什么情况下使用才能体现出区别呢?
path.resolve
该函数接受「零或多个」字符串类型的路径参数,并返回一个 normalized 的「绝对路径」。
path.resolve(path1, path2, ..., pathN)
有以下几个特点:
- 其中 zero-length 的参数会被忽略,比如
''(空字符串)和'.'(表示当前目录)。- 以
/开头的参数会被当作文件系统根路径,不以../或./开头的参数会被当作是目录。- 若参数不为字符串类型,则会抛出 TypeError。
- 若不传递任何参数时,返回 Node 进程的当前工作目录。因此
path.resolve() === process.cwd()结果为true。- 结果返回之前其内部也会做类似
path.normalize()的路径规范化处理。
看例子:
path.resolve('/a', 'b', 'c') // return: "/a/b/c"
path.resolve('/a', '/b', 'c') // return: "/b/c"
path.resolve('/a', '/b', '/c') // return: "/c"
其实在官网就描述得很清晰了。无非就是,「从右到左」一个一个参数开始解析,每解析一个就将其加到原来路径的「前面」,参数之间使用平台对应的路径分隔符连接。若能拼接成一个绝对路径,就停止解析并立即返回。如果将所有参数都解析完,仍然无法拼凑得出一个绝对路径,那么就讲这些参数的结果拼到当前工作目录中,以得出绝对路径。
因此,上述示例内部解析过程如下:
"c" -> "b/c" -> "/a/b/c"
"c" -> "/b/c"
"/c"
假设有 path.resolve('a', 'b'),就是 "b" -> "a/b" -> "process.cwd()/a/b" 的过程,相当于 path.resolve(process.cwd(), 'a', 'b')。其中 proccess.cwd() 就是当前工作目录。
个人认为,更好的理解倒是「从左往右」看,将 path.resolve() 方法看作 Shell 的 cd 操作,只是前者不管文件系统是否存在此目录或文件。如伪代码:
path.resolve('/a', '/b', 'c')
// 相当于
$ cd /a; cd /b; cd c
或许
path.resolve()称为path.cd()更让人豁然开朗吧。
path.join
该函数接受「零或多个」字符串类型的路径参数,返回一个所有参数拼接起来的(相对/绝对)路径。
path.join(path1, path2, ..., pathN)
有以下几个特点:
- 其中 zero-length 的参数会被忽略,比如
''(空字符串)和'.'(表示当前目录)。- 以
../开头的参数认为是上一级目录。- 第一个参数若以
/会被认为是根目录,其他以/开头的参数作用与./相同。- 若参数不为字符串类型,则会抛出 TypeError。
- 若不传递任何参数时,返回
.(当前目录)。- 结果返回之前其内部也会做类似
path.normalize()的路径规范化处理。
看例子:
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"
其实不用看那么多,换个角度去理解或许更清晰,两个步骤:
- 用相加运算符
+将所有参数连接起来(参数之间用/连接)。- 使用
path.normalize()对相加后的字符串路径作规范化处理。
有人可能会问,path.normalize() 又是干嘛的啊。很简单:把 ./、../ 翻译成对应路径;把多余无用的路径连接符干掉(如 a//b => a/b);将路径连接符转换为特定平台的连接符(比如 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"
区别
以几个示例做总结:
无参数时
path.resolve() // 返回当前工作目录,相当于 `process.cwd()`,是绝对路径。
path.join() // 返回 `.`(当前目录),是相对路径。
👆 请注意「当前工作目录」和「当前目录」的区别。
有多个参数,且中间参数以 / 开头
path.resolve('/a', '/b', 'c') // 返回 `/b/c`,绝对路径。
path.join('/a', '/b', 'c') // 返回 `/a/b/c`,绝对路径。
path.resolve('a', '/b', 'c') // 返回 `/b/c`,绝对路径。
path.join('a', '/b', 'c') // 返回 `a/b/c`,相对路径。
相信大家都懂了。
The end.