Разница между "module.exports" и "export" в модуле CommonJs Module
На этой странице (http://docs.nodejitsu.com/articles/getting-started/what-is-require) говорится, что "Если вы хотите установить объект экспорта на функцию или новый объект, вы должны использовать объект module.exports."
Мой вопрос - почему.
// right
module.exports = function () {
console.log("hello world")
}
// wrong
exports = function () {
console.log("hello world")
}
I console.logged результат (result=require(example.js)
), а первый - [Function]
, второй - {}
.
Не могли бы вы объяснить причину этого? Я прочитал сообщение здесь: module.exports и экспорт в Node.js. Это полезно, но не объясняет причину, почему она разработана таким образом. Будет ли проблема, если ссылка на экспорт будет возвращена напрямую?
Ответы
Ответ 1
module
- это простой объект JavaScript с свойством exports
. exports
- простая переменная JavaScript, которая устанавливается на module.exports
.
В конце вашего файла node.js будет в основном "возвращать" module.exports
в функцию require
. Упрощенный способ просмотра JS файла в Node может быть следующим:
var module = { exports: {} };
var exports = module.exports;
// your code
return module.exports;
Если вы установите свойство на exports
, например exports.a = 9;
, это также установит module.exports.a
, потому что объекты передаются как ссылки в JavaScript, а это означает, что если вы установите несколько переменных на один и тот же объект, они все те же объекты; поэтому exports
и module.exports
- это один и тот же объект.
Но если вы установите для exports
что-то новое, оно больше не будет установлено на module.exports
, поэтому exports
и module.exports
уже не являются одним и тем же объектом.
Ответ 2
Ответ Renee хорошо объяснен. Добавление к ответу с примером:
Node многое делает для вашего файла, и одним из важных является WRAPPING вашего файла. Внутри nodejs возвращается исходный код "module.exports". Давайте сделаем шаг назад и поймем обертку. Предположим, что у вас есть
greet.js
var greet = function () {
console.log('Hello World');
};
module.exports = greet;
приведенный выше код завершается как выражение IIFE (выражение с выражением немедленного вызова) внутри исходного кода nodejs следующим образом:
(function (exports, require, module, __filename, __dirname) { //add by node
var greet = function () {
console.log('Hello World');
};
module.exports = greet;
}).apply(); //add by node
return module.exports; //add by node
и вызывается вышеупомянутая функция (.apply()) и возвращается module.exports.
В это время module.exports и export указывают на одну и ту же ссылку.
Теперь представьте, что вы переписываете
greet.js как
exports = function () {
console.log('Hello World');
};
console.log(exports);
console.log(module.exports);
вывод будет
[Function]
{}
причина такова: module.exports - пустой объект. Мы ничего не установили в module.exports, а установили export = function()..... в новый greet.js. Таким образом, module.exports пуст.
Технически экспорт и module.exports должны указывать на ту же ссылку (thats correct!!). Но мы используем "=" при назначении функции().... для экспорта, который создает другой объект в памяти. Таким образом, module.exports и export производят разные результаты. Когда дело касается экспорта, мы не можем его переопределить.
Теперь представьте, что вы переписываете (это называется Мутация)
greet.js(ссылаясь на ответ Рене) как
exports.a = function() {
console.log("Hello");
}
console.log(exports);
console.log(module.exports);
вывод будет
{ a: [Function] }
{ a: [Function] }
Как вы видите, module.exports и export указывают на ту же ссылку, которая является функцией. Если вы установите свойство для экспорта, то оно будет установлено на module.exports, потому что в JS объекты проходят по ссылке.
Заключение всегда использует module.exports, чтобы избежать путаницы.
Надеюсь это поможет. Счастливое кодирование:)
Ответ 3
Кроме того, одна вещь, которая может помочь понять:
math.js
this.add = function (a, b) {
return a + b;
};
client.js
var math = require('./math');
console.log(math.add(2,2); // 4;
Отлично, в этом случае:
console.log(this === module.exports); // true
console.log(this === exports); // true
console.log(module.exports === exports); // true
Таким образом, по умолчанию "this" фактически равен module.exports.
Однако, если вы измените свою реализацию на:
math.js
var add = function (a, b) {
return a + b;
};
module.exports = {
add: add
};
В этом случае он будет работать нормально, однако "this" больше не равен module.exports, так как был создан новый объект.
console.log(this === module.exports); // false
console.log(this === exports); // true
console.log(module.exports === exports); // false
И теперь, что будет возвращено требованием, это то, что было определено внутри module.exports, а не этого или экспорта больше.
Другой способ сделать это:
math.js
module.exports.add = function (a, b) {
return a + b;
};
Или:
math.js
exports.add = function (a, b) {
return a + b;
};
Ответ 4
Ответ Рене о взаимосвязи между exports
и module.exports
довольно ясен, все о ссылках на javascript. Просто хочу добавить, что:
Мы видим это во многих модулях node:
var app = exports = module.exports = {};
Это позволит убедиться, что даже если мы изменили module.exports, мы все равно можем использовать экспорт, указав эти две переменные на один и тот же объект.