← Назад к вопросам

В чем разница между module.exports и exports в Node.js?

2.0 Middle🔥 202 комментариев
#Node.js и JavaScript

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между module.exports и exports в Node.js

Этот вопрос часто вызывает путаницу у разработчиков. Хотя оба используются для экспорта, между ними есть критическая разница в том, как они работают с ссылками и объектами.

Основная разница

// exports — это ссылка на module.exports
exports === module.exports  // true

// Но когда ты переназначаешь exports
exports = { name: 'John' };  // это НЕ меняет module.exports!

Как это работает внутри

Node.js оборачивает каждый модуль в функцию:

(function (exports, require, module, __filename, __dirname) {
  // Твой код здесь
  // exports и module.exports указывают на один и тот же объект
});

Первоначально:

exports = module.exports = {};  // одна и та же ссылка

Практические примеры

1. Правильный способ — присвоение к module.exports

// math.js
module.exports = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b,
};

// main.js
const math = require('./math');
console.log(math.add(5, 3));  // 8

2. Проблема — переназначение exports

// logger.js
exports = {
  log: (msg) => console.log(msg),
};

// main.js
const logger = require('./logger');
console.log(logger);  // {}  — ПУСТО!
// exports переназначена, но module.exports остался пуст

3. Правильное использование exports для добавления методов

// Этот подход работает потому что мы меняем объект, а не ссылку

// user.js
exports.getName = function() {
  return 'John';
};

exports.getAge = function() {
  return 30;
};

// Эквивалентно
module.exports.getName = function() {
  return 'John';
};

module.exports.getAge = function() {
  return 30;
};

// main.js
const user = require('./user');
console.log(user.getName());  // 'John'

Важный момент: ссылки vs значения

// РАБОТАЕТ — мы меняем свойства объекта
exports.method = () => console.log('Hello');
// Потому что exports указывает на module.exports

// НЕ РАБОТАЕТ — мы меняем саму ссылку
exports = { method: () => console.log('Hello') };
// Теперь exports указывает на новый объект, а module.exports остался прежним

Сложный пример

// Это НЕ работает
exports = () => console.log('Function');
// require вернет {} потому что module.exports не изменился

// Это РАБОТАЕТ
module.exports = () => console.log('Function');
// require вернет функцию

// Использование
const func = require('./module');
func();  // Function

Применение в современном Node.js

1. Экспорт объекта с методами

// database.js
module.exports = {
  connect() {
    console.log('Connected');
  },
  query(sql) {
    return [];
  },
};

2. Экспорт класса

// User.js
class User {
  constructor(name) {
    this.name = name;
  }
  
  getName() {
    return this.name;
  }
}

module.exports = User;

// main.js
const User = require('./User');
const user = new User('John');

3. Экспорт функции

// utils.js
module.exports = function formatDate(date) {
  return date.toLocaleDateString();
};

// main.js
const formatDate = require('./utils');
formatDate(new Date());  // '28.03.2026'

Избежание ошибок

// ❌ ПЛОХО — это не работает
exports = { value: 42 };

// ✅ ХОРОШО
module.exports = { value: 42 };

// ✅ ХОРОШО — добавление свойств
exports.value = 42;

// ✅ ХОРОШО (современный способ)
module.exports.value = 42;

Дебагинг

// Если ты не уверен что экспортируется
console.log('exports:', exports);
console.log('module.exports:', module.exports);
console.log('Одно и тоже?', exports === module.exports);

// После переназначения exports
exports = { test: 123 };
console.log('exports === module.exports:', false);
// Вот почему require не видит твой объект!

Правило большого пальца

Всегда используй module.exports, никогда не переназначай exports:

// ✅ ВСЕГДА ТАК
module.exports = { ... };
module.exports.method = function() { ... };

// ❌ НИКОГДА ТАК
exports = { ... };  // НЕ переназначай!

Почему это было так спроектировано?

Node.js основан на CommonJS, где exports был удобным сокращением для добавления свойств:

// Удобно писать
exports.method = () => {};

// Вместо
module.exports.method = () => {};

Но когда ты хочешь экспортировать что-то целое (объект, класс, функцию), нужно переназначить сам module.exports, а не exports.

Современный Node.js

В наши дни рекомендуется использовать ES6 модули:

// export.js — современный способ
export const add = (a, b) => a + b;
export default { add };

// import.js
import { add } from './export.js';

Но CommonJS все еще используется повсеместно в существующих проектах, поэтому понимание этой разницы критично для работы с Node.js.

В чем разница между module.exports и exports в Node.js? | PrepBro