Wywołać funkcję „lokalną” w module.exports z innej funkcji w module.exports?


327

Jak wywołać funkcję z poziomu innej funkcji w module.exportsdeklaracji?

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();
  }

}

Próbuję uzyskać dostęp do funkcji fooz poziomu funkcji bari otrzymuję:

TypeError: Object # nie ma metody „foo”

Jeśli zmienię this.foo()tylko na foo():

ReferenceError: foo nie jest zdefiniowany


4
Przetestowałem Twój kod i nie mam błędów. Funkcja bar zwraca wartość niezdefiniowaną, ponieważ nie ma instrukcji return. Czy na pewno testujesz poprawnie?
Ferchi

1
Testowany w wersji węzła v8.12.0i nie generuje już błędu. barnie ma deklaracji zwrotu, więc uruchomienie console.log(bla.bar())po prostu zwracaundefined
VladNeacsu

Odpowiedzi:


351

Zmień this.foo()namodule.exports.foo()


1
@NamNguyen Calling exports.foo()wydaje się trochę niewygodny i trudny do odczytania.
Afshin Mehrabani

4
Myślę, że to lepsze niż zaakceptowana odpowiedź. Jeśli zdefiniujesz funkcje poza zakresem eksportu, doda to dodatkowy poziom pośredniczości i chociaż może być czasem pożądane, sprawia, że ​​jest bardziej skomplikowane, refaktoryzacja, np. Zmiana nazwy funkcji, znalezienie użycia funkcji itp.
Pierre Henry

1
bezpośrednia odpowiedź na pytanie
Kermit_ice_tea

8
module.exports.foo()i exports.foo()nie pracuj dla mnie z Node.js v5.8.0.
betweenbrain 15.07.16

14
exports.foo () nie działa, ale module.exports.foo () działa z NodeJS v6.9.1
R. Canser Yanbakan

191

Możesz zadeklarować swoje funkcje poza module.exportsblokiem.

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

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

Następnie:

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

11
co jeśli chciałbym uzyskać dostęp do właściwości obiektu z metody?
Rockstar5645,

1
Dostaję TypeError: twojaKlasa.youMethod nie jest funkcją, kiedy to zrobiłem. Używam węzła w wersji 6.9.1. Czy musisz mieć wyciąg zwrotny? Nie mam instrukcji return, ponieważ cały mój kod jest asynchroniczny w funkcjach.
Brett Mathe,

1
Ładne porównanie różnych stylów - gist.github.com/kimmobrunfeldt/10848413
Tadas V.

Bardzo fajne wdrożenie! +1
realnsleo

2
Lub, bardziej zwięźle, używając ES6,module.exports = { foo, bar, }
Let Me Tink About It

118

Możesz to również zrobić, aby uczynić go bardziej zwięzłym i czytelnym. Oto, co widziałem w kilku dobrze napisanych modułach open source:

var self = module.exports = {

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

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

}

Czy ta wersja Node.js jest specyficzna? Próbuję tego z wersją 5.0.0 i rejestrowanie jest niezdefiniowane.
betweenbrain 15.07.16

1
@doublejosh Czy ... przeczytałeś pytanie? Pyta, jak wywołać jedną wyeksportowaną funkcję z drugiej. Nie ma to nic wspólnego z ograniczeniami dostępu.
Pozew Fund Moniki w

1
Tak, przeczytałem to, proszę ponownie przeczytać. Ta odpowiedź powoduje, że foo () jest eksportowane z modułem, co jest sprzeczne z punktem funkcji „lokalnej” wywoływanej tylko w module.
doublejosh

66

Można również zapisać odwołanie do globalnego zasięgu modułu poza definicją (module.) Exports.somemodule:

var _this = this;

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

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

To czystsze rozwiązanie!
IvanZh,

nie ma potrzeby tego i możesz po prostu użyć tego tam, gdzie jest to potrzebne
Yuki

używane thisbezpośrednio, nie trzeba deklarować_this
Dariusz

1
Ta sugestia jest przydatna, gdy thisjuż nie jest słuszna this. (
Obiecuje

Najbardziej podoba mi się to rozwiązanie, ponieważ daje ono również przykład określania zakresu w modułach NodeJS.
miguelmorin

40

Inną opcją i bliższą oryginalnemu stylowi OP jest umieszczenie obiektu, który chcesz wyeksportować, w zmiennej i odwołanie się do tej zmiennej w celu wywołania innych metod w obiekcie. Następnie możesz wyeksportować tę zmienną i gotowe.

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
Jest to szczególnie użyteczne, ponieważ kod tam się wywołuje Service.foo(), a kod klienta będzie również dzwonił Service.foo()z tą samą nazwą.
Vince Bowdren

To idealna odpowiedź!
Jayant Varshney

16

Począwszy od wersji 13 Node.js , możesz skorzystać z modułów ES6 .

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

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

Zgodnie z podejściem klasowym:

class MyClass {

    foo() {
        return 'foo';
    }

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

module.exports = new MyClass();

Spowoduje to utworzenie instancji klasy tylko raz, ze względu na buforowanie modułu Node:
https://nodejs.org/api/modules.html#modules_caching


i jak można wywołać metodę statyczną przy takim podejściu?
Plixxer,

@CodeofGod Po prostu wywołaj to tak, jak nazwałbyś każdą inną metodę statyczną. W tym przypadku, jeśli foobyła statyczna nazwałbyś go od wewnątrz bartak: MyClass.foo().
m.spyratos,

tak, rozumiem, ale jak nazwałbyś to z kontrolera, który go importuje, tak jak ... const oAccounts = wymagany ("...");
Plixxer

Możesz wyeksportować rzeczywistą klasę, a nie instancję klasy. W ten sposób możesz użyć jego metod statycznych. Jeśli jednak będziesz musiał użyć metod jego instancji, będziesz musiał utworzyć instancję klasy w kontrolerze.
m.spyratos

6

Aby rozwiązać problem, wprowadziłem kilka zmian w pliku bla.js i działa,

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

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

i bez modyfikacji w app.js

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

1
This.foo () na pasku funkcji nie działa ... musi być foo ()
Falcoa
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.