Пространство имён: область видимости или адрес?
Дата публикации: 2022-11-03Сравним понятие namespace в Java, PHP и JavaScript. В общем смысле пространство имён — набор знаков для идентификации объектов; оно делает имена уникальными и позволяет на них ссылаться. Оно также задаёт контекст, поэтому слова «пространство имён» и «область видимости» часто употребляют рядом.
Java
В Java пространство имён называется package:
package java.awt.event;
Каждый класс обычно расположен в отдельном файле, а пакеты образуют иерархию. Поэтому исходник java.applet.AppletContext ожидаемо находится по адресу ./java/applet/AppletContext.java, а java.awt.event.ActionListener — в ./java/awt/event/ActionListener.java. Файловая система обеспечивает уникальность идентификаторов, а пакет создаёт контекст: классы без явного модификатора доступа доступны друг другу внутри пакета.
Для глобальной уникальности Java заимствует DNS: владельцу company.com предлагается использовать пакет com.company. Поэтому в Java пространство имён прежде всего адресует код и уже затем ограничивает область видимости.
PHP
В PHP пространства имён появились с версии 5.3 и ещё ближе к файловой системе:
namespace Zend;
Технически в одном файле допустимо несколько пространств имён, но это не рекомендуемая практика. Они вкладываются друг в друга и могут адресоваться абсолютно или относительно — подобно пути в файловой системе, где alias напоминает символьную ссылку.
namespace Project;
use Project\ModuleA as ModA;
$modA = new ModuleA();
$modA2 = new ModA();
PHP даёт более гибкую адресацию, чем Java, но в обоих языках разработчик и IDE находят исходник по полному имени (FQN). И, как у Java-пакета, пространство имён создаёт свой контекст.
JavaScript
В самом JavaScript нет конструкций namespace или package. Классический ответ на вопрос «как объявить namespace?» — создать именованную область видимости:
const MyNamespace = (function () { /* ... */ })();
Такой «namespace» в JS прежде всего про изоляцию, а не про адрес. Вложенные области могут содержать одинаково названную функцию:
const MyNamespace = (() => {
function myFunc() { console.log('Main space.'); }
return { fn: myFunc };
})();
((mainSpace) => {
function myFunc() { console.log('Nested space.'); }
mainSpace.subSpace = { fn: myFunc };
})(MyNamespace);
Во время выполнения они изолированы, но для человека и IDE трудно получить уникальный адрес каждой myFunc. «Copy Reference» часто даёт только имя функции, а «Find Usage» становится малополезным в очень большом проекте. Отчасти это объясняет появление TypeScript.
Современный JavaScript с ES-модулями и npm намного ближе к потребностям больших проектов, но единое, общепринятое правило глобальной адресации элементов кода всё ещё нужно проекту задавать дисциплиной и инструментами.
Вывод
Пространство имён — и адрес, и область видимости, как обычный почтовый адрес и реальное место. Каждый адрес указывает на место, но не у каждого места есть собственный адрес. Главное назначение namespace — помочь разработчику адресовать исходный код, а не компьютеру обратиться к объекту во время выполнения.