Пространство имён: область видимости или адрес?

Дата публикации: 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 — помочь разработчику адресовать исходный код, а не компьютеру обратиться к объекту во время выполнения.