
В процессе разработки часто используется Node.js, который использует возможности V8 для расширения возможностей JS. В Node.js мы можем использовать модуль пути, которого нет в JS. Чтобы лучше познакомиться с приложением, давайте взглянем на него ~
Версия этой статьи для Node.js — 16.14.0. , а исходный код этой статьи взят отсюда Версия. Я надеюсь, что после прочтения этой статьи всем будет полезно прочитать исходный код.
используется для обработки путей к файлам и каталогам. Этот модуль предоставляет некоторые функции инструментов, которые удобно разрабатывать разработчикам, чтобы помочь нам в принятии сложных решений о пути и повышении эффективности разработки. Например:
Настройте псевдонимы в проекте. Конфигурация псевдонима облегчает нам обращение к файлам и позволяет избежать пошагового поиска вверх.
перелюбить: {
псевдоним: {
// __dirname путь к каталогу 'src', в котором находится текущий файл: path.resolve(__dirname, './src'),
// текущий рабочий каталог процесса.cwd '@': path.join(process.cwd(), 'src'),
},
} В веб-пакете выходной путь файла также может быть сгенерирован в указанное место с помощью нашей собственной конфигурации.
модуль.экспорт = {
запись: './path/to/my/entry/file.js',
выход: {
путь: path.resolve(__dirname, 'dist'),
имя файла: 'my-first-webpack.bundle.js',
},
} Или для операций с папками
пусть fs = require("fs");
пусть путь = требуется («путь»);
// Удалить папку let deleDir = (src) => {
// Читаем папку let Children = fs.readdirSync(src);
Children.forEach(item => {
пусть childpath = path.join(src, item);
// Проверяем, существует ли файл let file = fs.statSync(childpath).isFile();
если (файл) {
// Удаляем файл, если он существует fs.unlinkSync(childpath)
} еще {
//Продолжаем обнаруживать папку deleDir(childpath)
}
})
// Удаляем пустую папку fs.rmdirSync(src)
}
deleDir("../floor") кратко описывает сценарии использования пути. Далее мы изучим механизм его выполнения и то, как он реализуется на основе его использования.

Когда вводится модуль пути и вызывается инструментальная функция пути, будет введена логика обработки собственного модуля.
Используйте функцию _load , чтобы использовать имя модуля, которое вы указали в качестве идентификатора, чтобы определить, что загружаемый модуль является собственным модулем JS. После этого функция loadNativeModule будет использоваться для использования идентификатора для поиска соответствующего кода ASCII из _source (. строка исходного кода, сохраняющая собственный модуль JS). Данные загружаются в собственный модуль JS.
Выполните файл lib/path.js и используйте процесс для определения операционной системы. В зависимости от операционной системы может быть дифференциальная обработка рабочих символов при обработке файла, но метод примерно тот же. После обработки он возвращается в исходное состояние. звонивший.
возвращает абсолютный путь текущего пути
.
разрешить (... аргументы) {
пусть разрешеноDevice = '';
пусть разрешенный хвост = '';
пусть разрешено Абсолютное = ложь;
// Обнаружение параметров справа налево for (let i = args.length - 1; i >= -1; i--) {
...
}
//Нормализованный путьsolvedTail =normalizeString(resolvedTail, !resolvedAbsolute, '\', isPathSeparator);
вернуть решенное Абсолютно?
`${resolvedDevice}\${resolvedTail}` :
`${resolvedDevice}${resolvedTail}` ||
} 
Получить путь по параметрам, пройтись по полученным параметрам, начать склейку, когда длина параметров больше или равна 0, выполнить нестроковую проверку по склеенному пути, если есть несовпадающие параметры , throw new ERR_INVALID_ARG_TYPE(name, 'string', value) , если требования соблюдены, длина пути будет оценена. Если есть значение, для следующего шага будет использоваться += путь.
пусть путь;
если (я >= 0) {
путь = аргументы [я];
// внутренние/валидаторы
validateString (путь, 'путь');
// Если длина пути равна 0, он выйдет непосредственно из цикла for приведенного выше блока кода if (path.length === 0) {
продолжать;
}
} еще если (resolvedDevice.length === 0) {
//Длина разрешенного устройства равна 0, присвойте значение path как текущий рабочий каталог path =process.cwd();
} еще {
// Присвоение значения объекту среды или текущему рабочему каталогу path =process.env[`=${resolvedDevice}`] ||process.cwd();
если (путь === не определено ||
(StringPrototypeToLowerCase(StringPrototypeSlice(path, 0, 2)) !==
StringPrototypeToLowerCase(resolvedDevice) &&
StringPrototypeCharCodeAt(путь, 2) === CHAR_BACKWARD_SLASH)) {
// Оцениваем путь по непустым и абсолютным путям, чтобы получить путь path = `${resolvedDevice}\`;
}
} 
Попробуйте сопоставить корневой путь, определите, существует ли только один разделитель пути ('') или путь является абсолютным, затем отметьте абсолютный путь и установите для флага перехвата rootEnd значение 1 (нижний индекс). Если второй элемент по-прежнему является разделителем пути (''), определите значение перехвата как 2 (нижний индекс) и используйте last , чтобы сохранить значение перехвата для последующего принятия решения.
Продолжайте определять, является ли третий элемент разделителем пути (''). Если да, то это абсолютный путь, а идентификатор перехвата rootEnd равен 1 (нижний индекс), но это также может быть путь UNC (servernamesharename). , имя сервера имя сервера). Если есть другие значения, перехваченное значение будет продолжать увеличиваться и читать следующие значения, а также использовать firstPart для сохранения значения третьего бита, чтобы это значение можно было получить при объединении каталога, и сохранять последнее и перехваченное значения. последователь прекратить судебное решение.
const len = путь.длина;
let rootEnd = 0 // индекс конца перехвата пути let device = '' // корень диска D:, C:
let isAbsolute = false // Является ли это корневым путем диска const code = StringPrototypeCharCodeAt(path, 0);
// длина пути равна 1
если (длин === 1) {
// Для абсолютного пути существует только один разделитель пути if (isPathSeparator(code)) {
кореньКонец = 1;
isAbsolute = правда;
}
} Еще если (isPathSeparator(код)) {
// Может быть корнем UNC, начинающимся с разделителя , по крайней мере один из которых является абсолютным путем (UNC или другим)
isAbsolute = правда;
// Начинаем сопоставление двойного разделителя путей if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) {
пусть j = 2;
пусть последний = j;
// Сопоставление одного или нескольких разделителей, не являющихся путями, while (j < len &&
!isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
j++;
}
if (j <len && j !== последний) {
const firstPart = StringPrototypeSlice (путь, последний, j);
последний = j;
// Сопоставление одного или нескольких разделителей пути while (j < len &&
isPathSeparator (StringPrototypeCharCodeAt (путь, j))) {
j++;
}
if (j <len && j !== последний) {
последний = j;
в то время как (j < len &&
!isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
j++;
}
if (j === len || j !== последний) {
устройство=
`\\${firstPart}\${StringPrototypeSlice(path, Last, j)}`;
rootEnd = j;
}
}
}
} еще {
кореньКонец = 1;
}
// Пример определения корневого каталога диска: D:, C:
} else if (isWindowsDeviceRoot(code) && StringPrototypeCharCodeAt(path, 1) === CHAR_COLON) {
устройство = StringPrototypeSlice (путь, 0, 2);
кореньКонец = 2;
if (len > 2 && isPathSeparator(StringPrototypeCharCodeAt(path, 2))) {
isAbsolute = правда;
кореньКонец = 3;
}
} Определите путь и сгенерируйте его, проверьте, существует ли корневой каталог диска, или определите, является resolvedAbsolute абсолютным путем.
//Определить корневой каталог диска if (device.length > 0) {
//solveDevice имеет значение if (resolvedDevice.length > 0) {
если (StringPrototypeToLowerCase(устройство) !==
StringPrototypeToLowerCase(resolvedDevice))
продолжать;
} еще {
//solveDevice не имеет значения и ему присваивается значение корневого каталога дискаsolveDevice = device;
}
}
// Абсолютный путь if (resolvedAbsolute) {
// Существует конечный цикл, если корневой каталог диска существует (resolvedDevice.length > 0)
перерыв;
} еще {
// Получаем префикс пути для склейкиsolveTail =
`${StringPrototypeSlice(path, rootEnd)}\${resolvedTail}`;
решеноАбсолютное = естьАбсолютное;
if (isAbsolute &&solveDevice.length > 0) {
// Цикл завершается, когда корень диска существует.
}
} join выполняет объединение путей на основе входящих фрагментов пути

Получите несколько параметров, используйте определенные разделители в качестве разделителей для соединения всех параметров пути вместе и создайте новый нормализованный путь.
После получения параметров проверьте их. Если параметров нет, он вернет непосредственно «.». В противном случае он будет проходить и проверять каждый параметр с помощью встроенного метода validateString . Если есть какое-либо нарушение, напрямую throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
join escape-символа заключается в том, что при его использовании отдельно считается, что он экранирует строку после косой черты, поэтому для экранирования обратной косой черты используются двойные обратные косые черты ('').
Наконец, объединенная строка проверяется и возвращается в заданном формате.
if (args. length === 0)
возвращаться '.';
пусть присоединился;
пусть первая часть;
// Обнаружение параметров слева направо for (let i = 0; i < args.length; ++i) {
const arg = args[i];
// внутренние/валидаторы
validateString(arg, 'путь');
if (длина аргумента > 0) {
если (присоединился === не определено)
// Назначаем первую строку объединению и используем переменную firstPart, чтобы сохранить первую строку для последующего использования join = firstPart = arg;
еще
// join имеет значение, выполняем операцию += сращивания join += `\${arg}`;
}
}
если (присоединился === не определено)
return '.'; В оконной системе требуется обработка сетевого пути из-за использования обратной косой черты ('') и пути UNC (в основном относится к полному имени ресурсов Windows 2000 в локальной сети), ('') представляет собой формат сетевого пути, поэтому метод join установленный в Win32, будет перехватываться по умолчанию.
Если обратная косая черта ('') совпадает, slashCount будет увеличиваться. Если найдено более двух обратных косых черт (''), объединенный путь будет перехвачен и вручную объединен и экранирован обратной косой чертой (. '').
пусть потребностиReplace = true;
пусть slashCount = 0;
// Извлекаем код кода первой строки в последовательности в соответствии с StringPrototypeCharCodeAt и сопоставляем его с определенным кодом кода с помощью метода isPathSeparator if (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 0))) {
++слэшКаунт;
const firstLen = firstPart.length;
если (firstLen > 1 &&
isPathSeparator(StringPrototypeCharCodeAt(firstPart, 1))) {
++слэшКаунт;
если (firstLen > 2) {
если (isPathSeparator(StringPrototypeCharCodeAt(firstPart, 2)))
++слэшКаунт;
еще {
потребностиЗаменить = ложь;
}
}
}
}
если (нуждыЗаменить) {
while (slashCount < join.length &&
isPathSeparator(StringPrototypeCharCodeAt(joined, slashCount))) {
слэшКаунт++;
}
если (слэшКаунт >= 2)
join = `\${StringPrototypeSlice(joined, slashCount)}`;
} Сортировка результатов выполнения
| Разрешение | соединения | |
|---|---|---|
| не имеет параметров | . | Абсолютный путь к текущему файлу | .
| Параметры | не имеют абсолютного | пути. |
| Первый параметр — это абсолютный путь. | текущего файла ивставляется в абсолютный путь | последующих неабсолютных путей. |
| Пост-параметр пути является параметром абсолютного пути | . Путь перезаписывает абсолютный путь текущего файла и перезаписывает | путь, соединенный с ним. | предварительные параметры.
| Первый параметр — (./) | и имеет последующие параметры. Параметр сращивания абсолютного пути текущего файла не имеет последующих параметров. Абсолютный путь к текущему файлу — Путь | имеет последующие параметры, а путь сращивается. по последующим параметрам не имеет последующих параметров. (./) |
| Пост-параметр имеет (./) | Разбираемый параметр сращивания абсолютного пути | имеет последующие параметры. Склеенный путь не имеет последующих параметров, а сращивание (/ |
| ) первый параметр — (../), | и есть последующие параметры. Параметры склейки после каталога последнего уровня, охватывающего абсолютный путь текущего файла, не имеют последующих параметров. Каталог последнего уровня, охватывающий абсолютный путь текущего файла, | имеет последующие параметры. . Сращивание Для последующих параметров нет последующих параметров (../) |
| Пост-параметр имеет (../ | )Каталог верхнего уровня, в котором появляется (../), будет перезаписан. перезаписан. Каталог верхнего уровня будет перезаписан. После возврата (/) последующие параметры будут склеены и | появившийся каталог верхнего уровня (../) будет перезаписан. Сколько слоев указано в суффиксе, будет перезаписано. После перезаписи верхнего каталога |
. После исходного кода метод resolve обработает параметры, учтет форму пути и выдаст в конце абсолютный путь. При его использовании, если вы выполняете такие операции, как файлы, рекомендуется использовать метод resolve . Для сравнения, метод resolve вернет путь, даже если нет параметров для работы пользователя, и путь будет обработан. в процессе исполнения. Метод join выполняет только стандартизированное объединение входящих параметров, что более практично для создания нового пути и может быть создано по желанию пользователя. Однако каждый метод имеет свои преимущества. Вам следует выбрать подходящий метод в соответствии с вашими сценариями использования и потребностями проекта.