Ostatnio pracowałem z nodejs i wciąż mam do czynienia z systemem modułów, więc przepraszam, jeśli jest to oczywiste pytanie. Chcę kod mniej więcej taki jak poniżej:
a.js (główny plik uruchamiany z węzłem)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var a = require("./a");
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
Wydaje się, że moim problemem jest to, że nie mogę uzyskać dostępu do wystąpienia ClassA z poziomu wystąpienia ClassB.
Czy istnieje poprawny / lepszy sposób strukturyzacji modułów, aby osiągnąć to, czego chcę? Czy istnieje lepszy sposób udostępniania zmiennych między modułami?
Odpowiedzi:
Chociaż node.js zezwala na
require
zależności cykliczne , jak zauważyłeś, może być dość niechlujny i prawdopodobnie lepiej będzie zreorganizować kod, aby go nie potrzebował. Może stwórz trzecią klasę, która wykorzysta pozostałe dwie, aby osiągnąć to, czego potrzebujesz.źródło
exports = {}
na górze swojego kodu, a następnieexports = yourData
na końcu kodu. Dzięki tej praktyce unikniesz prawie wszystkich błędów wynikających z zależności cyklicznych.Spróbuj włączyć właściwości
module.exports
, zamiast całkowicie je zastępować. Np.module.exports.instance = new ClassA()
Wa.js
,module.exports.ClassB = ClassB
wb.js
. Kiedy tworzysz cykliczne zależności modułów,module.exports
żądany moduł otrzyma odwołanie do niekompletnego z wymaganego modułu, do którego możesz dodać inne właściwości, ale kiedy ustawisz całośćmodule.exports
, w rzeczywistości utworzysz nowy obiekt, którego żądany moduł nie ma sposób dostępu.źródło
module.exports
bez całkowitego zastępowania go, aby umożliwić innym klasom „skonstruowanie” instancji klasy?[EDYTUJ] to nie rok 2015 i większość bibliotek (np. Ekspresowych) dokonało aktualizacji z lepszymi wzorcami, więc zależności cykliczne nie są już potrzebne. Zalecam po prostu ich nie używać .
Wiem, że wykopuję tutaj starą odpowiedź ... Problem polega na tym, że module.exports jest definiowany po tym, jak potrzebujesz ClassB. (co pokazuje link JohnnyHK) Zależności cykliczne działają świetnie w Node, są po prostu definiowane synchronicznie. Prawidłowo używane rozwiązują wiele typowych problemów z węzłami (np. Uzyskiwanie dostępu do express.js
app
z innych plików)Po prostu upewnij się, że niezbędne eksporty są zdefiniowane, zanim będziesz potrzebować pliku z zależnością cykliczną.
To się zepsuje:
To zadziała:
Cały czas używam tego wzorca, aby uzyskać dostęp do express.js
app
w innych plikach:źródło
app = express()
Czasami wprowadzenie trzeciej klasy jest naprawdę sztuczne (jak radzi JohnnyHK), więc oprócz Ianzza: Jeśli chcesz zamienić module.exports, na przykład jeśli tworzysz klasę (jak plik b.js w powyższy przykład), jest to również możliwe, po prostu upewnij się, że w pliku, który rozpoczyna cykliczne żądanie, instrukcja „module.exports = ...” występuje przed instrukcją require.
a.js (główny plik uruchamiany z węzłem)
b.js
źródło
Rozwiązaniem jest „zadeklarowanie dalej” obiektu eksportu przed zażądaniem jakiegokolwiek innego kontrolera. Więc jeśli uporządkujesz wszystkie swoje moduły w ten sposób i nie napotkasz żadnych takich problemów:
źródło
exports.foo = function() {...}
zamiast tego po prostu użyłem. Zdecydowanie załatwił sprawę. Dzięki!module.exports
jest już zwykłym obiektem, więc twoja linia "deklaracji do przodu" jest zbędna.Rozwiązaniem wymagającym minimalnej zmiany jest rozszerzenie,
module.exports
a nie nadpisanie.a.js - punkt wejścia aplikacji i moduł używający metody do z b.js *
b.js - moduł używający metody do z a.js
Będzie działać i produkować:
Chociaż ten kod nie zadziała:
a.js
b.js
Wynik:
źródło
underscore
, ES6Object.assign()
mogą wykonać tę samą pracę,_.extend()
co w tej odpowiedzi.A co z leniwym wymaganiem tylko wtedy, gdy tego potrzebujesz? Więc twój b.js wygląda następująco
Oczywiście dobrą praktyką jest umieszczanie wszystkich wymaganych instrukcji na wierzchu pliku. Ale są sytuacje, w których wybaczam sobie wybieranie czegoś z niepowiązanego modułu. Nazwij to hackiem, ale czasami jest to lepsze niż wprowadzenie dalszej zależności lub dodanie dodatkowego modułu lub dodanie nowych struktur (EventEmitter itp.)
źródło
Inną metodą, którą widziałem, jest eksportowanie w pierwszym wierszu i zapisywanie jej jako zmiennej lokalnej w następujący sposób:
Zwykle używam tej metody, czy znasz jakieś jej wady?
źródło
module.exports.func1 =
,module.exports.func2 =
Możesz to łatwo rozwiązać: po prostu wyeksportuj swoje dane, zanim będziesz potrzebować czegokolwiek innego w modułach, w których używasz module.exports:
classA.js
classB.js
źródło
Podobnie jak w przypadku odpowiedzi Lanzza i Setecta, korzystam z następującego wzoru:
W
Object.assign()
kopiuje członków doexports
obiektu, który już został dany do innych modułów.=
Zadaniem jest logicznie zbędny, ponieważ jest po prostu ustawieniemodule.exports
na sobie, ale używam go, ponieważ pomaga moja IDE (WebStorm) uznać, żefirstMember
jest własnością tego modułu, więc „przejść do -> Deklaracja” (Cmd-B) a inne narzędzia będą działać z innych plików.Ten wzorzec nie jest zbyt ładny, więc używam go tylko wtedy, gdy trzeba rozwiązać problem cyklicznej zależności.
źródło
Oto szybkie obejście, które znalazłem w pełni.
W pliku „a.js”
W pliku „b.js” zapisz co następuje
W ten sposób w następnej iteracji klasy pętli zdarzeń zostaną poprawnie zdefiniowane, a te instrukcje będą działać zgodnie z oczekiwaniami.
źródło
Właściwie skończyło się na tym, że wymagałem mojej zależności od
nie ładne, ale działa. Jest to bardziej zrozumiałe i uczciwe niż zmiana b.js (na przykład tylko rozszerzenie modułów.export), która poza tym jest doskonała.
źródło
Jednym ze sposobów uniknięcia tego jest nie wymaganie jednego pliku w innym, po prostu przekazanie go jako argumentu funkcji, czego potrzebujesz w innym pliku. W ten sposób nigdy nie powstanie zależność cykliczna.
źródło