В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.
При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.
Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».
Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this
. Возьмем этот пример:
public class Some {
private int id;
public int getId(){
return this.id;
}
public setId( int newId ) {
this.id = newId;
}
}
И в другом месте вашего кода:
Some reference = new Some(); // Point to a new object of type Some()
Some otherReference = null; // Initiallly this points to NULL
reference.setId( 1 ); // Execute setId method, now private var id is 1
System.out.println( reference.getId() ); // Prints 1 to the console
otherReference = reference // Now they both point to the only object.
reference = null; // "reference" now point to null.
// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );
// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...
Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference
и otherReference
оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.
Настройка module.exports
позволяет вызвать функцию database_module
как функцию, когда required
. Просто установка exports
не позволяет экспортировать функцию, потому что узел экспортирует ссылки на объект module.exports
. Следующий код не позволит пользователю вызывать функцию.
Следующие действия не будут работать.
exports = nano = function database_module(cfg) {return;}
Следующее будет работать, если установлено module.exports
.
module.exports = exports = nano = function database_module(cfg) {return;}
console
var func = require('./module.js');
// the following line will **work** with module.exports
func();
В основном node.js не экспортирует объект, который в настоящий момент ссылается exports
, но экспортирует свойства того, что изначально ссылается exports
. Хотя Node.js экспортирует ссылки на объект module.exports
, что позволяет вам называть его как функцию.
Они устанавливают как module.exports
, так и exports
, чтобы гарантировать, что exports
не ссылается на предыдущий экспортируемый объект. Установив оба параметра, вы используете exports
как сокращенное название и избегаете потенциальных ошибок позже по дороге.
Использование exports.prop = true
вместо module.exports.prop = true
сохраняет символы и позволяет избежать путаницы.
Из docs
Переменная экспорта доступна в пределах области уровня файла модуля и ей присваивается значение module.exports перед оценкой модуля .
Он позволяет использовать ярлык, так что module.exports.f = ... может быть написан более лаконично как export.f = .... Однако имейте в виду, что, как и любая переменная, если новый значение присваивается экспорту, оно больше не привязано к module.exports:
blockquote>Это просто переменная, указывающая на module.exports.
var a = {},md={};
// Во-первых, экспорт и module.exports указывают один и тот же пустой Object
exp = a;//exports =a;
md.exp = a;//module.exports = a;
exp.attr = "change";
console.log(md.exp);//{attr:"change"}
// Если вы укажете exp на другой объект, а не на объект, то это свойство для другого объекта. Md.exp будет пустым. Object {}
var a ={},md={};
exp =a;
md.exp =a;
exp = function(){ console.log('Do nothing...'); };
console.log(md.exp); //{}
«Если вы хотите, чтобы корневой каталог вашего модуля был функцией (например, конструктором), или если вы хотите экспортировать полный объект в одно задание вместо того, чтобы создавать его по одному свойству за раз, назначьте его модулю. экспорт вместо экспорта ». - http://nodejs.org/api/modules.html
В основном ответ заключается в том, что действительно происходит, когда модуль требуется с помощью инструкции require
. Предполагая, что это первый раз, когда требуется модуль.
Например:
var x = require('file1.js');
содержимое файла file1.js:
module.exports = '123';
Когда выше, создается объект Module
. Его конструкторская функция:
function Module(id, parent) {
this.id = id;
this.exports = {};
this.parent = parent;
if (parent && parent.children) {
parent.children.push(this);
}
this.filename = null;
this.loaded = false;
this.children = [];
}
Как вы видите, каждый объект модуля имеет свойство с именем exports
. Это то, что в конечном итоге возвращается как часть require
.
Следующий шаг требует обернуть содержимое файла file1.js в анонимную функцию, как показано ниже:
(function (exports, require, module, __filename, __dirname) {
//contents from file1.js
module.exports = '123;
});
И эта анонимная функция вызывается следующим образом, module
здесь ссылается на созданный ранее объект Module
.
(function (exports, require, module, __filename, __dirname) {
//contents from file1.js
module.exports = '123;
}) (module.exports,require, module, "path_to_file1.js","directory of the file1.js");
Как мы видим внутри функции, формальный аргумент exports
относится к module.exports
. По сути, это удобство, предоставляемое программисту модуля.
Однако это удобство должно выполняться с осторожностью. В любом случае, если вы пытаетесь назначить новый объект для экспорта, убедитесь, что мы делаем это таким образом.
exports = module.exports = {};
Если мы сделаем это следующим образом неправильным способом , module.exports
по-прежнему будет указывая на объект, созданный как часть экземпляра модуля.
exports = {};
. Как результат добавление чего-либо к указанному выше объекту экспорта не будет иметь никакого эффекта для объекта module.exports, и ничто не будет экспортировано или возвращено как часть требуемого.
func()
терпит неудачу в ответе @ Уильяма!
– turtledove
17 July 2015 в 02:38
exports = module.exports = app;
в последнюю строку кода. Похоже, что module.exports
будет экспортироваться, и мы никогда не будем использовать exports
, потому что снова он находится на последней строке кода. Итак, почему бы нам просто не добавить module.exports = app;
– lvarayut
15 December 2015 в 05:19
Я прошел некоторые тесты, и я думаю, что это может пролить свет на предмет ...
app.js
:
var ...
, routes = require('./routes')
...;
...
console.log('@routes', routes);
...
версии /routes/index.js
:
exports = function fn(){}; // outputs "@routes {}"
exports.fn = function fn(){}; // outputs "@routes { fn: [Function: fn] }"
module.exports = function fn(){}; // outputs "@routes function fn(){}"
module.exports.fn = function fn(){}; // outputs "@routes { fn: [Function: fn] }"
Я даже добавил новые файлы:
./routes/index.js
:
module.exports = require('./not-index.js');
module.exports = require('./user.js');
./routes/not-index.js
:
exports = function fn(){};
./routes/user.js
:
exports = function user(){};
Получаем вывод «@routes {}»
./routes/index.js
:
module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');
./routes/not-index.js
:
exports = function fn(){};
./routes/user.js
:
exports = function user(){};
Получаем вывод «@routes {fn: {}, user: {}}"
< hr> ./routes/index.js
:
module.exports.fn = require('./not-index.js');
module.exports.user = require('./user.js');
./routes/not-index.js
:
exports.fn = function fn(){};
./routes/user.js
:
exports.user = function user(){};
Получаем output "@routes {user: [Function: user]}« Если мы изменим user.js
на { ThisLoadedLast: [Function: ThisLoadedLast] }
, мы получим вывод «@routes {ThisLoadedLast: [Function: ThisLoadedLast]}».
Но если мы изменим ./routes/index.js
...
./routes/index.js
:
module.exports.fn = require('./not-index.js');
module.exports.ThisLoadedLast = require('./user.js');
./routes/not-index.js
:
exports.fn = function fn(){};
./routes/user.js
:
exports.ThisLoadedLast = function ThisLoadedLast(){};
... мы получаем «@routes {fn: {fn: [Function: fn]}, ThisLoadedLast: {ThisLoadedLast: [Function: ThisLoadedLast]}}"
Поэтому я предлагаю всегда использовать module.exports
в определениях вашего модуля.
Я не полностью и вы можете понять, что происходит внутри с узлом, но, пожалуйста, прокомментируйте, если вы можете больше понять это, поскольку я уверен, что это помогает.
- Счастливое кодирование
Давайте создадим один модуль с двумя способами:
Один из способов
var aa = {
a: () => {return 'a'},
b: () => {return 'b'}
}
module.exports = aa;
Второй способ
exports.a = () => {return 'a';}
exports.b = () => {return 'b';}
И вот как требует () будет интегрировать модуль.
Первый способ:
function require(){
module.exports = {};
var exports = module.exports;
var aa = {
a: () => {return 'a'},
b: () => {return 'b'}
}
module.exports = aa;
return module.exports;
}
Второй способ
function require(){
module.exports = {};
var exports = module.exports;
exports.a = () => {return 'a';}
exports.b = () => {return 'b';}
return module.exports;
}
exports
и module.exports
одинаковы, если вы не переназначаете exports
в своем модуле.
Самый простой способ подумать об этом - это думать, что эта строка неявно находится в верхней части каждый модуль.
var exports = module.exports = {};
Если в вашем модуле вы переназначаете exports
, вы переназначите его в своем модуле, и он больше не будет module.exports
. Вот почему, если вы хотите экспортировать функцию, вы должны сделать:
module.exports = function() { ... }
Если вы просто назначили function() { ... }
на exports
, вы переназначили exports
, чтобы больше не указывать на module.exports
.
Если вы не хотите каждый раз ссылаться на свою функцию на module.exports
, вы можете сделать:
module.exports = exports = function() { ... }
Обратите внимание, что module.exports
самый левый аргумент.
Прикрепление свойств к exports
не совпадает с тем, что вы не переназначаете его. Вот почему это работает
exports.foo = function() { ... }
. Тонкая разница заключается в том, как объекты передаются по ссылке в JavaScript.
exports
и module.exports
оба указывают на тот же объект. exports
является переменной, а module.exports
является атрибутом объекта модуля.
Скажем, я пишу что-то вроде этого:
exports = {a:1};
module.exports = {b:12};
exports
и module.exports
сейчас указывают на разные объекты. Изменение экспорта больше не изменяет module.exports.
Когда функция импорта проверяет module.exports
, она получает {b:12}
почему оба используются здесь
blockquote>Я считаю, что они просто хотят быть ясными, что
module.exports
,exports
иnano
указывают на ту же функцию - позволяя вы можете использовать любую переменную для вызова функции внутри файла.nano
предоставляет некоторый контекст того, что делает функция.
exports
не будет экспортироваться (толькоmodule.exports
будет), так зачем же переписывать это?Комплимент подробностей ограничивает риск будущих ошибок, например, используя
exports
вместоmodule.exports
в файле. Он также дает разъяснения, чтоmodule.exports
иexports
на самом деле указывают на одно и то же значение.
module.exports
vsexports
Пока вы надеваете 't переназначить
module.exports
илиexports
(и вместо этого добавить значения к объекту, к которому они обращаются), вы не будете иметь никаких проблем и можете безопасно использоватьexports
для более кратких.При назначении не-объекту они теперь указывают на разные места, которые могут сбивать с толку, если вы не намерены хотеть
module.exports
быть чем-то конкретным (например, функцией).Установка
exports
на не-объект не имеет особого смысла, поскольку вам нужно будет установитьmodule.exports = exports
в конце, чтобы иметь возможность использовать его в других файлах.let module = { exports: {} }; let exports = module.exports; exports.msg = 'hi'; console.log(module.exports === exports); // true exports = 'yo'; console.log(module.exports === exports); // false exports = module.exports; console.log(module.exports === exports); // true module.exports = 'hello'; console.log(module.exports === exports); // false module.exports = exports; console.log(module.exports === exports); // true
Зачем присваивать функцию
module.exports
функции?Более краткий! Сравните, насколько короче второй пример:
helloWorld1.js:module.exports.hello = () => console.log('hello world');
app1.js:
helloWorld2.js:let sayHello = require('./helloWorld1'); sayHello.hello; // hello world
module.exports = () => console.log('hello world');
app2.js:
let sayHello = require('./helloWorld2'); sayHello; // hello world
Я просто делаю какой-то тест, оказывается, что внутри модуля модуля nodejs он должен выглядеть примерно так:
var module.exports = {};
var exports = module.exports;
so:
exports = function(){}; // this will not work! as it make the exports to some other pointer
module.exports = function(){}; // it works! cause finally nodejs make the module.exports to export.
exports.abc = function(){}; // works!
exports.efg = function(){}; // works!
module.exports = function(){}; // from now on we have to using module.exports to attach more stuff to exports.
module.exports.a = 'value a'; // works
exports.b = 'value b'; // the b will nerver be seen cause of the first line of code we have do it before (or later)
module.exports
- это своего рода «реальная сделка», с которой узел удаляется, но в какой-то момент вам нужно будет добавить все ваши exports
в module.exports
, если вы не используете exports.namespace
(случай 2 выше), который в этом случае, похоже, как Node, запустил extends(module.exports, exports);
, добавив все [пространства имен] exports
к объекту module.exports
? Другими словами, если вы используете exports
, вы, вероятно, захотите установить на нем свойства?
– Cody
25 March 2014 в 00:04
1.exports -> использовать как утилиту singleton 2. module-exports -> использовать в качестве логических объектов, таких как сервис, модель и т. д.
Изначально функция module.exports=exports
и require
возвращает объект module.exports
.
, если мы добавим свойство к объекту, скажем exports.a=1
, затем module.exports и export все еще относятся к одному и тому же объекту. Поэтому, если мы вызываем require и присваиваем модуль переменной, то переменная имеет свойство a, а ее значение равно 1;
. Но если мы переопределим один из них, например exports=function(){}
, то они теперь разные: экспорт относится к новому объекту, а module.exports относится к исходному объекту. И если нам нужен файл, он не вернет новый объект, так как module.exports не относится к новому объекту.
Для меня я буду продолжать добавлять новое свойство или переопределять их оба новый объект. Просто переопределить одно не правильно. И имейте в виду, что module.exports
- настоящий босс.
you are the real boss
:) большое спасибо
– Vikas Bansal
19 June 2017 в 08:18
module.exports
и exports
указывают на то же function database_module(cfg) {...}
. 1| var a, b;
2| a = b = function() { console.log("Old"); };
3| b = function() { console.log("New"); };
4|
5| a(); // "Old"
6| b(); // "New"
Вы можете изменить b
в строке 3 на a
, выход - наоборот. Вывод: a
и b
независимы. module.exports = exports = nano = function database_module(cfg) {...}
эквивалентно: var f = function database_module(cfg) {...};
module.exports = f;
exports = f;
Предполагалось, что это module.js
, что требуется foo.js
. Преимущества module.exports = exports = nano = function database_module(cfg) {...}
теперь ясны: В foo.js
, поскольку module.exports
- require('./module.js')
: var output = require('./modules.js')();
В moduls.js
: вы можете использовать exports
вместо module.exports
. Итак, вы будете счастливы, если оба exports
и module.exports
указывают на одно и то же.
Это показывает, как require()
работает в своей простейшей форме, выдержка из Eloquent JavaScript
Проблема Невозможно, чтобы модуль напрямую экспортировал значение, отличное от экспорта объект, такой как функция. Например, модуль может захотеть экспортировать только конструктор типа объекта, который он определяет. В настоящее время он не может этого сделать, потому что требование всегда использует объект exports
, который он создает в качестве экспортируемого значения.
Решение. Предоставьте модули с другой переменной module
, которая является объектом, обладающим свойством exports
. Это свойство первоначально указывает на пустой объект, созданный require, но может быть перезаписано другим значением, чтобы экспортировать что-то еще.
function require(name) {
if (name in require.cache)
return require.cache[name];
var code = new Function("exports, module", readFile(name));
var exports = {}, module = {exports: exports};
code(exports, module);
require.cache[name] = module.exports;
return module.exports;
}
require.cache = Object.create(null);
Даже если вопрос был дан ответ и принят давно, я просто хочу поделиться своими двумя центами:
Вы можете себе представить, что в самом начале вашего файла есть что-то вроде (только для объяснения) :
var module = new Module(...);
var exports = module.exports;
[/g1]
Итак, что бы вы ни делали, помните, что module.exports
и NOT exports
будут возвращены из вашего модуля, когда вы 're требующий этого модуля откуда-то еще.
Итак, когда вы делаете что-то вроде:
exports.a = function() {
console.log("a");
}
exports.b = function() {
console.log("b");
}
Вы добавляете к объекту 2 функции' a 'и' b ' module.exports тоже, поэтому typeof
возвращаемый результат будет object
: { a: [Function], b: [Function] }
Конечно, это тот же результат, который вы получите, если используете module.exports
в этом вместо exports
.
Это тот случай, когда вы хотите, чтобы ваш module.exports вел себя как контейнер экспортируемых значений. Принимая во внимание, что если вы хотите экспортировать функцию-конструктор, вы должны знать об использовании module.exports
или exports
; (помните еще раз, что module.exports будет возвращен, когда вам потребуется что-то, а не экспорт).
module.exports = function Something() {
console.log('bla bla');
}
Теперь тип возвращаемого результата равен 'function'
, и вы можете потребовать его и сразу вызвать: var x = require('./file1.js')();
, потому что вы возвращаете возвращаемый результат как функцию.
Однако, используя exports
вы не можете использовать что-то вроде:
exports = function Something() {
console.log('bla bla');
}
var x = require('./file1.js')(); //Error: require is not a function
Поскольку с exports
ссылка больше не указывает на объект, где module.exports
указывает, поэтому нет отношения между exports
и module.exports
. В этом случае module.exports все еще указывает на пустой объект {}
, который будет возвращен.
Принятый ответ из другой темы также должен помочь: Проходит ли Javascript по ссылке?
module.exports
из модуля, например, в этом пакете npm
: github.com/tj/consolidate.js/blob/master/lib/consolidate .js
– CodyBugstein
9 February 2015 в 08:46
exports.a = function(){}; works, exports = function(){} doesn't work
– cirpo
12 June 2015 в 19:00
exports
? Почему бы просто не использовать module.exports
, если это просто переменная переназначения? Кажется, меня смущает.
– jedd.ahyoung
4 July 2015 в 16:30
var module = new Module();
и var exports = module.exports;
, полностью объясняют, что происходит.
– jeffwtribble
30 September 2016 в 17:46
Я нашел эту ссылку полезной для ответа на указанный выше вопрос.
http://timnew.me/blog/2012/04/20/exports-vs-module-exports-in- node-js /
Чтобы добавить к другим сообщениям, модуль модуля в узле выполняет
var exports = module.exports
перед выполнением вашего кода. Поэтому, когда вы хотите экспортировать = foo, вы, вероятно, захотите сделать module.exports = exports = foo, но с помощью export.foo = foo должно быть отлично
Вот хорошее описание, написанное о модулях узлов в node.js в книге действий из публикации Manning. То, что в конечном итоге экспортируется в ваше приложение, - module.exports. экспорт настраивается просто как глобальная ссылка на module.exports, которая изначально определяется как пустой объект, к которому вы можете добавить свойства. Таким образом, export.myFunc является просто сокращением для module.exports.myFunc. В результате, если экспорт установлен на что-либо еще, он разбивает ссылку между modules.exports и export. Поскольку module.exports - это то, что действительно экспортируется, экспорт больше не работает должным образом - он больше не ссылается на модуль .exports. Если вы хотите сохранить эту ссылку, вы можете снова сделать ссылку на export.exports следующим образом:
module.exports = exports = db;
Вот результат
console.log("module:");
console.log(module);
console.log("exports:");
console.log(exports);
console.log("module.exports:");
console.log(module.exports);
Также:
if(module.exports === exports){
console.log("YES");
}else{
console.log("NO");
}
//YES
Примечание: только спецификация CommonJS позволяет использовать переменную экспорта для раскрытия открытых элементов. Таким образом, именованный шаблон экспорта является единственным, который действительно совместим с спецификацией CommonJS. Использование module.exports - это расширение, предоставляемое Node.js для поддержки более широкого диапазона шаблонов определения модулей.
в файле node.js узла js используется для запуска системы module.load. Каждый раз, когда узел выполняет файл, он переносит содержимое вашего js-файла, как показано далее
'(function (exports, require, module, __filename, __dirname) {',+
//your js file content
'\n});'
из-за этой упаковки внутри ur js исходный код, вы можете получить доступ к экспорту, требованию, модулю и т. д. Этот подход используется, потому что нет другого способа получить функциональность, написанную в файле js другому.
Затем узел выполняет эту завернутую функцию используя c ++. в этот момент объект экспорта, который передается в эту функцию, будет заполнен.
вы можете видеть внутри этих параметров параметров параметров и модуля. Фактически экспорт является публичным членом функции конструктора модуля.
смотрите следующий код
скопируйте этот код в b.js
console.log("module is "+Object.prototype.toString.call(module));
console.log("object.keys "+Object.keys(module));
console.log(module.exports);
console.log(exports === module.exports);
console.log("exports is "+Object.prototype.toString.call(exports));
console.log('----------------------------------------------');
var foo = require('a.js');
console.log("object.keys of foo: "+Object.keys(foo));
console.log('name is '+ foo);
foo();
скопируйте этот код в a.js
exports.name = 'hello';
module.exports.name = 'hi';
module.exports.age = 23;
module.exports = function(){console.log('function to module exports')};
//exports = function(){console.log('function to export');}
теперь выполняется с использованием узла
module is [object Object]
object.keys id,exports,parent,filename,loaded,children,paths
{}
true
object.keys foo: name is function () {console.log ('функция для экспорта модулей')} функция для экспорта модулей
теперь удаляет прокомментированную строку в a.js и комментирует строку выше эту строку и удалить последнюю строку b.js и запустить.
в мире javascript вы не можете переназначить объект, который передается как параметр, но вы можете изменить публичный член функции, когда объект этой функции задан как параметр для другого function
использует module.exports и только если вы хотите получить функцию при использовании ключевого слова require. в приведенном выше примере мы var foo = require (a.js); вы можете видеть, что мы можем вызвать foo как функцию,
так объясняет документацию узла. Объект экспорта создается системой модулей. Иногда это неприемлемо, многие хотят, чтобы их модуль был экземпляром для некоторого класса. Для этого назначьте желаемый объект экспорта в module.exports. "
nano
в вашем примере? – ostergaard 12 January 2013 в 11:06nano.version = '3.3'
вместоmodule.exports.version = '3.3'
, который читается немного более четко. (Обратите внимание, чтоnano
является локальной переменной, объявлена немного раньше, чем устанавливается экспорт экспорта .) – josh3736 14 January 2013 в 22:19module.exports
, но not i>exports
, будет ли мой код работать? Спасибо за любую помощь! – Asad Saeeduddin 21 February 2013 в 02:42module.exports
– William 22 February 2013 в 01:19