Export: примеры (JAVASCRIPT)

Экспорт модулей в JavaScript: полный обзор
Раздел: Модули, Экспорт
export(declaration (any)): -

Основы экспорта в JavaScript

Ключевое слово export используется в JavaScript для экспорта функций, объектов, примитивных значений или классов из модуля, чтобы они стали доступными для других модулей с помощью оператора import. Экспорт применяется только в модулях (файлах с типом module).

Использование: Экспорт необходим для создания модульной архитектуры в приложениях, позволяя разбивать код на переиспользуемые и изолированные части.

Варианты синтаксиса:

  • Именованный экспорт (Named Export): Позволяет экспортировать несколько значений из модуля, указывая их имена. Может использоваться как при объявлении, так и после него.
  • Экспорт по умолчанию (Default Export): Позволяет экспортировать одно главное значение из модуля (функцию, класс или объект).
  • Реэкспорт (Re-export): Позволяет агрегировать и экспортировать значения из других модулей.

У оператора export нет аргументов или возвращаемых значений в традиционном понимании функции. Это декларация, которая определяет, какие части модуля становятся публичными.

Базовые примеры использования

Именованный экспорт при объявлении

Экспорт константы и функции непосредственно в момент их создания.

// module.js
export const apiKey = '123abc';
export function sum(a, b) {
  return a + b;
}
export class Calculator {
  multiply(x, y) { return x * y; }
}
// При импорте в другом файле:
// import { apiKey, sum, Calculator } from './module.js';

Именованный экспорт списком

Экспорт нескольких значений, объявленных ранее.

// module.js
const greeting = 'Hello';
const dbUrl = 'localhost:5432';
function log(message) { console.log(message); }

export { greeting, dbUrl, log };

Экспорт по умолчанию

Экспорт одного основного значения из модуля.

// userService.js
export default class UserService {
  getUser(id) { return { id, name: 'John' }; }
}

// или для функции
export default function(config) {
  console.log(config);
}
// При импорте:
// import UserService from './userService.js'; // Имя может быть любым

Комбинированный экспорт

Использование именованного экспорта и экспорта по умолчанию вместе.

// utils.js
export const version = '1.0';
export function helper() {}
const mainUtil = () => {};
export default mainUtil;
// Импорт:
// import mainUtil, { version, helper } from './utils.js';

Альтернативные системы модулей в JavaScript

CommonJS (используется в Node.js)

Использует module.exports и require(). Это синхронная система, исторически применяемая в серверной среде Node.js.

// Экспорт
module.exports = { key: 'value' };
// или
exports.item = function() {};

// Импорт
const lib = require('./lib');

Когда использовать: В проектах Node.js, не перешедших на нативные ES-модули, или в инструментах сборки, таких как Webpack или Browserify, которые могут транспилировать код.

AMD (Asynchronous Module Definition)

Использует функцию define. Создана для асинхронной загрузки модулей в браузере. Наиболее известная реализация — RequireJS.

define(['dependency1', 'dependency2'], function(dep1, dep2) {
  return {
    myExport: function() {}
  };
});

Когда использовать: В устаревших браузерных проектах, где важна асинхронная загрузка без сборщиков.

Предпочтения: Для современных веб-приложений и библиотек стандартом являются ES-модули (export/import) из-за их нативной поддержки в браузерах и Node.js, статической анализируемости и асинхронной природы.

Экспорт в других языках программирования

Python (import/from)

В Python каждый файл .py является модулем. Экспорт всего содержимого модуля управляется соглашениями и списком __all__.

# mymodule.py
def public_func():
    return "Hello"

def _private_func():
    return "Secret"

__all__ = ['public_func'] # Определяет, что импортируется при from module import *
# Импорт в другом файле
from mymodule import public_func
print(public_func()) # Hello
# _private_func не будет доступна при импорте через *

PHP (namespace/use)

PHP использует пространства имен (namespaces) и ключевые слова use для импорта. Экспорт как таковой отсутствует — доступно все, что объявлено в файле.

// File: MyApp/Utils.php
<?php
namespace MyApp;

class Utils {
    public static function filter($data) { return $data; }
}

function helper() {}
// Импорт в другом файле
<?php
use MyApp\Utils;
use function MyApp\helper;

Utils::filter([]);
helper();

C/C++ (header files)

В C/C++ используется механизм заголовочных файлов (.h), которые содержат объявления функций и переменных. Определения находятся в файлах реализации (.c/.cpp).

// mylib.h - заголовочный файл ("экспорт")
#ifndef MYLIB_H
#define MYLIB_H
extern int global_var; // Объявление глобальной переменной
int add(int a, int b); // Объявление функции
#endif

// mylib.c - файл реализации
#include "mylib.h"
int global_var = 10;
int add(int a, int b) { return a + b; }

Ключевое отличие: В отличие от JavaScript, где export является частью языка и контролирует видимость на уровне модуля, в C/C++ видимость регулируется линковщиком, а в PHP и Python — в основном соглашениями и пространствами имен.

Распространенные ошибки

Использование export вне модуля

Ключевое слово export работает только внутри файлов-модулей.

<script>
export let x = 1; // ОШИБКА!
</script>

<script type="module">
export let x = 1; // Корректно
</script>
SyntaxError: Unexpected token 'export'

Попытка экспорта необъявленной переменной

// module.js
export { someVariable }; // ОШИБКА: someVariable не объявлена выше
SyntaxError: The requested module does not provide an export named 'someVariable'

Несколько экспортов по умолчанию в одном модуле

В одном модуле может быть только один export default.

// module.js
export default function() {};
export default class {}; // ОШИБКА: Повторный экспорт по умолчанию
SyntaxError: Duplicate export of 'default'

Ошибки при реэкспорте

Попытка реэкспорта несуществующего именованного экспорта.

// aggregator.js
export { nonExistent } from './someModule.js'; // ОШИБКА
SyntaxError: The requested module does not provide an export named 'nonExistent'

Изменения и современное состояние

Синтаксис export был стандартизирован в спецификации ECMAScript 2015 (ES6). С тех пор его ядро остаётся стабильным.

Динамический импорт (ES2020)

Хотя напрямую не меняет export, появление выражения import() для динамической загрузки модулей расширило экосистему. Модули с export могут теперь загружаться условно.

if (userNeedsFeature) {
  import('./advancedModule.js')
    .then(module => {
      module.advancedFunction();
    });
}

Поддержка в Node.js

Ранние версии Node.js поддерживали только CommonJS. Нативная поддержка ES-модулей (с export/import) стабильно доступна с Node.js версии 14.x и выше. Для использования необходимо указать "type": "module" в package.json или использовать расширение файла .mjs.

Экспорт полей пространства имен (Export Namespace)

Синтаксис export * as namespace from 'module' был добавлен и теперь широко поддерживается, позволяя реэкспортировать все именованные экспорты как один объект.

Расширенные и специализированные примеры

Реэкспорт с переименованием и агрегация

Создание единой точки входа для библиотеки, состоящей из нескольких модулей.

Пример javascript
// lib/index.js (основной файл библиотеки)
export { default as AuthService } from './auth.js';
export { getUser, setUser } from './user.js';
export * as constants from './constants.js'; // Экспорт всех как объект

export { fetchApi as fetch } from './network.js'; // Реэкспорт с переименованием
// Использование в приложении
import { AuthService, fetch, constants } from './lib/index.js';
console.log(constants.API_URL);

Экспорт изменяемых привязок (live bindings)

Именованный экспорт создаёт "живую привязку" к переменной, а не копию значения.

Пример javascript
// counterModule.js
export let counter = 0;
export function increment() {
  counter++;
}

// main.js
import { counter, increment } from './counterModule.js';
console.log(counter); // 0
increment();
console.log(counter); // 1 (значение изменилось!)
0
1

Экспорт с условиями (паттерн)

Динамическое определение того, что экспортировать, невозможно, но можно использовать паттерн агрегации.

Пример javascript
// featureDetect.js
import { FeatureA } from './features/FeatureA.js';
import { FeatureB } from './features/FeatureB.js';

const enabledFeatures = [];
if (supportsFeatureA) enabledFeatures.push(FeatureA);
if (supportsFeatureB) enabledFeatures.push(FeatureB);

// Экспортируем только то, что доступно
export { FeatureA, FeatureB }; // Экспорт всегда статичен
// Динамический экспорт невозможен, но можно экспортировать объект:
export const features = { FeatureA, FeatureB };

Кольцевые зависимости (Circular Dependencies)

Экспорт позволяет создавать кольцевые зависимости, но их следует избегать. Модули загружаются корректно благодаря "живым привязкам".

Пример javascript
// moduleA.js
import { funcB } from './moduleB.js';
export function funcA() {
  console.log('A');
  funcB();
}

// moduleB.js
import { funcA } from './moduleA.js';
export function funcB() {
  console.log('B');
  // funcA(); // Вызовет потенциальную бесконечную рекурсию
}

Экспорт встроенных объектов (polyfills)

Экспорт для расширения или модификации встроенных объектов в рамках модуля.

Пример javascript
// arrayUtils.js
if (!Array.prototype.customFlat) {
  Array.prototype.customFlat = function() { /* реализация */ };
}
// Экспортируем сам патч как функцию по умолчанию
export default function patchArray() {
  // код патча выше
}

// Также можно экспортировать утилиты, не загрязняя глобальную область видимости
export function flattenArray(arr) { /* чистая функция */ }

JS export function comments

En
Export Exports functions, objects, or primitives from a module