Вызвать «локальную» функцию в module.exports из другой функции в module.exports?


327

Как вы вызываете функцию из другой функции в module.exportsобъявлении?

app.js
var bla = require('./bla.js');
console.log(bla.bar());
bla.js
module.exports = {

  foo: function (req, res, next) {
    return ('foo');
  },

  bar: function(req, res, next) {
    this.foo();
  }

}

Я пытаюсь получить доступ к функции fooизнутри функции bar, и я получаю:

Ошибка типа: у объекта # нет метода 'foo'

Если я перехожу this.foo()на просто foo()я получаю:

ReferenceError: foo не определено


4
Я проверил ваш код и не имею ошибок. Функция bar возвращает неопределенное значение, поскольку не имеет оператора возврата. Вы уверены, что тестируете правильно?
Ферчи

1
Протестировано в версии узла v8.12.0и больше не выдает ошибку. barне имеет оператора возврата, поэтому выполнение console.log(bla.bar())просто возвращаетundefined
VladNeacsu

Ответы:


351

Изменить this.foo()наmodule.exports.foo()


1
@NamNguyen Вызов exports.foo()кажется немного неловким и трудным для чтения.
Афшин Мехрабани

4
Я думаю, что это лучше, чем принятый ответ. Если вы определяете функции вне области экспорта, это добавляет дополнительный уровень косвенности, и, хотя иногда это может быть желательно, это усложняет процесс рефакторинга, например, переименования функции, поиска использования функции и т. Д.
Пьер Генри

1
прямой ответ на вопрос
Kermit_ice_tea

8
module.exports.foo()и exports.foo()не работают для меня с Node.js v5.8.0.
мозгом

14
exports.foo () не работает, но module.exports.foo () работает с NodeJS v6.9.1
R. Canser Yanbakan

191

Вы можете объявить свои функции за пределами module.exportsблока.

var foo = function (req, res, next) {
  return ('foo');
}

var bar = function (req, res, next) {
  return foo();
}

Затем:

module.exports = {
  foo: foo,
  bar: bar
}

11
Что делать, если я хотел получить доступ к свойствам объекта из метода?
Rockstar5645

1
Я получаю TypeError: yourClass.youMethod не является функцией, когда я сделал это. Я использую версию узла 6.9.1. Вы должны иметь заявление о возврате? У меня нет операторов возврата, так как весь мой код асинхронен в функциях.
Бретт Мате

1
Хорошее сравнение разных стилей - gist.github.com/kimmobrunfeldt/10848413
Тадас В.

Очень хорошая реализация! +1
realnsleo

3
Или, если говорить более кратко, используя ES6,module.exports = { foo, bar, }
позвольте мне рассказать об этом

118

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

var self = module.exports = {

  foo: function (req, res, next) {
    return ('foo');
  },

  bar: function(req, res, next) {
    self.foo();
  }

}

Это конкретная версия Node.js? Я пытаюсь это с v5.8.0, и она не определена.
мозгом

1
@doublejosh Ты ... ты читал вопрос? Он спрашивает, как вы вызываете одну экспортированную функцию из другой. Это не имеет ничего общего с ограничениями доступа.
Фонд Моника иск

1
Да, я прочитал это, пожалуйста, перечитайте. Этот ответ делает foo () экспортированным с модулем, что противоречит точке «локальной» функции, вызываемой только внутри модуля.
doublejosh

66

Вы также можете сохранить ссылку на глобальную область модуля за пределами определения (module.) Exports.somemodule:

var _this = this;

exports.somefunction = function() {
   console.log('hello');
}

exports.someotherfunction = function() {
   _this.somefunction();
}

Это более чистое решение!
ИванЖ

нет необходимости в _this, и вы можете просто использовать это там, где вам это нужно
Юки

используется thisнапрямую, не нужно объявлять_this
Darius

1
Это предложение полезно когда-то thisуже не правильно this. (Обещания и обратные вызовы)
Эндрю МакОлаш

Мне больше всего нравится это решение, потому что оно также дает пример области видимости в модулях NodeJS.
Мигельморин

40

Другой вариант, более близкий к первоначальному стилю OP, состоит в том, чтобы поместить объект, который вы хотите экспортировать, в переменную и ссылаться на эту переменную, чтобы вызывать другие методы объекта. Затем вы можете экспортировать эту переменную, и все готово.

var self = {
  foo: function (req, res, next) {
    return ('foo');
  },
  bar: function (req, res, next) {
    return self.foo();
  }
};
module.exports = self;

25
const Service = {
  foo: (a, b) => a + b,
  bar: (a, b) => Service.foo(a, b) * b
}

module.exports = Service

3
Это особенно удобно, потому что ваш код вызывает Service.foo(), и ваш клиентский код также будет вызываться Service.foo()с тем же именем.
Винс Боудрен

Это идеальный ответ!
Джаянт Варшней

16

Начиная с Node.js версии 13, вы можете воспользоваться модулями ES6 .

export function foo() {
    return 'foo';
}

export function bar() {
    return foo();
}

Следуя подходу класса:

class MyClass {

    foo() {
        return 'foo';
    }

    bar() {
        return this.foo();
    }
}

module.exports = new MyClass();

Это создаст экземпляр класса только один раз из-за кэширования модуля узла:
https://nodejs.org/api/modules.html#modules_caching


и как можно вызвать статический метод с этим подходом?
Plixxer

@CodeofGod Просто вызовите его так же, как любой другой статический метод. В этом случае, если fooбыла статичной бы вы назвали его с внутренней стороны, barкак это: MyClass.foo().
m.spyratos

да, я получаю это, но как бы вы назвали это с контроллера, который импортирует его как ... const oAccounts = require ("...");
Plixxer

Вы можете экспортировать реальный класс, а не экземпляр класса. Таким образом, вы можете использовать его статические методы. Если затем вам понадобится использовать методы его экземпляра, вам придется создать экземпляр класса в вашем контроллере.
m.spyratos

6

Чтобы исправить вашу проблему, я сделал несколько изменений в bla.js, и он работает,

var foo= function (req, res, next) {
  console.log('inside foo');
  return ("foo");
}

var  bar= function(req, res, next) {
  this.foo();
}
module.exports = {bar,foo};

и никаких изменений в app.js

var bla = require('./bla.js');
console.log(bla.bar());

1
В функциональной панели this.foo () не работает ... он должен быть foo ()
Falcoa
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.