Wzorzec modułu JavaScript z przykładem [zamknięty]


136

Nie mogę znaleźć żadnych dostępnych przykładów pokazujących, jak dwa (lub więcej) różne moduły są połączone, aby ze sobą współpracować.

Chciałbym więc zapytać, czy ktoś ma czas na napisanie przykładu wyjaśniającego, jak moduły współpracują ze sobą.


To wszystko zmieniło się w ciągu ostatnich czterech lat, ale dzięki gorliwej nadmiernej moderacji te nieaktualne informacje będą krążyć wiecznie . Oto strona MDN o modułach ES6.
bbsimonbb

Odpowiedzi:


256

Aby podejść do wzorca projektowania modułowego, musisz najpierw zrozumieć następujące pojęcia:

Wyrażenie funkcji wywoływane natychmiastowo (IIFE):

(function() {
      // Your code goes here 
}());

Istnieją dwa sposoby korzystania z tych funkcji. 1. Deklaracja funkcji 2. Wyrażenie funkcyjne.

Tutaj używamy wyrażenia funkcyjnego.

Co to jest przestrzeń nazw? Teraz, jeśli dodamy przestrzeń nazw do powyższego fragmentu kodu

var anoyn = (function() {
}());

Co to jest domknięcie w JS?

Oznacza to, że jeśli zadeklarujemy jakąkolwiek funkcję z dowolnym zakresem zmiennej / wewnątrz innej funkcji (w JS możemy zadeklarować funkcję wewnątrz innej funkcji!), To zawsze będzie liczyć ten zakres funkcji. Oznacza to, że każda zmienna w funkcji zewnętrznej będzie zawsze czytana. Nie odczyta zmiennej globalnej (jeśli istnieje) o tej samej nazwie. Jest to również jeden z celów stosowania wzorca projektowania modułowego, unikającego konfliktu nazw.

var scope = "I am global";
function whatismyscope() {
    var scope = "I am just a local";
    function func() {return scope;}
    return func;
}
whatismyscope()()

Teraz zastosujemy te trzy koncepcje, o których wspomniałem powyżej, aby zdefiniować nasz pierwszy wzorzec projektowania modułowego:

var modularpattern = (function() {
    // your module code goes here
    var sum = 0 ;

    return {
        add:function() {
            sum = sum + 1;
            return sum;
        },
        reset:function() {
            return sum = 0;    
        }  
    }   
}());
alert(modularpattern.add());    // alerts: 1
alert(modularpattern.add());    // alerts: 2
alert(modularpattern.reset());  // alerts: 0

jsfiddle dla powyższego kodu.

Celem jest ukrycie zmiennej dostępności przed światem zewnętrznym.

Mam nadzieję że to pomoże. Powodzenia.


czy lepiej byłoby nazwać życie? do celów semantycznych i lepszego śledzenia stosu? czy zmieniłoby to cokolwiek w kodzie?
Jeroen

2
Twój pierwszy przykład (function() { /* Your code goes here */}());to w rzeczywistości IIFE (natychmiastowe wywołanie wyrażenia funkcyjnego), ok, jest anonimowy, ponieważ nie ma nazwy, więc możesz nawet nazwać go IIAFE (natychmiastowo wywołując anonimowe wyrażenie funkcyjne). Zobacz więcej na temat IIFE na stackoverflow.com/questions/ 2421911 /…
Adrien Bądź

dlaczego użyto instrukcji return? jeśli pominiemy return {}, wtedy funkcja dodawania i resetowania będzie publiczna i przypuszczam, że mogą uzyskać dostęp do lokalnej sumy zmiennych? czy mam rację?
Mou

Twój drugi przykład wygląda jak przedmiot, czy nie mam racji?
The Reason

4
To nie odpowiada na pytanie OP. Jest to opis wzorca modułu, a nie przykład tego, jak wiele modułów może współpracować ze sobą zgodnie z oczekiwaniami PO.
Erik Trautman

39

Naprawdę poleciłbym każdemu, kto podejmuje ten temat, przeczytanie bezpłatnej książki Addy Osmani:

„Nauka wzorców projektowych JavaScript”.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/

Ta książka bardzo mi pomogła, kiedy zaczynałem pisać łatwiejszy w utrzymaniu JavaScript i nadal używam go jako odniesienia. Spójrz na jego różne implementacje wzorców modułów, wyjaśnia je naprawdę dobrze.


Polecam również przeczytanie mojego artykułu na temat „Definitive Module Pattern”, który nie jest omówiony w książce Addy Osmani: github.com/tfmontague/definitive-module-pattern
tfmontague

1
Jak to się ma do „Wzorów JavaScript”
Stoyana

4
Książka Stoyana jest znacznie bardziej wszechstronna. Obejmuje nie tylko wzorce wysokiego poziomu, ale także bardziej szczegółowo omawia inne najlepsze praktyki JS.
Code Novitiate

1
recenzje na temat „Learning JavaScript Design Patterns” amazon.com/product-reviews/1449331815
Adrien Be

3
recenzje „JavaScript Patterns” autorstwa Stoyana Stefanova amazon.com/product-reviews/0596806752 . Uwaga: która wydaje się znacznie lepsza niż ta z „Learning JavaScript Design Patterns”
Adrien Be

19

Pomyślałem, że rozszerzę powyższą odpowiedź, mówiąc o tym, jak dopasować moduły razem do aplikacji. Czytałem o tym w książce Douga Crockforda, ale javascript był dla mnie nowicjuszem, ale wciąż było trochę tajemnicze.

Pochodzę z ac # background, więc dodałem terminologię, która jest dla mnie przydatna.

HTML

Będziesz miał jakiś plik HTML najwyższego poziomu. Pomyśl o tym jako o pliku projektu. Każdy plik javascript, który dodajesz do projektu, chce się w to znaleźć, niestety nie masz do tego wsparcia narzędziowego (używam IDEA).

Musisz dodać pliki do projektu z tagami skryptów takimi jak:

        <script type="text/javascript" src="app/native/MasterFile.js" /></script>
        <script type="text/javascript" src="app/native/SomeComponent.js" /></script>

Wygląda na to, że zwinięcie tagów powoduje niepowodzenie - chociaż wygląda na XML, to naprawdę coś z bardziej szalonymi zasadami!

Plik przestrzeni nazw

MasterFile.js

myAppNamespace = {};

Otóż ​​to. Służy to tylko do dodania pojedynczej zmiennej globalnej, w której pozostanie reszta naszego kodu. Możesz także zadeklarować zagnieżdżone przestrzenie nazw tutaj (lub w ich własnych plikach).

Moduł (y)

SomeComponent.js

myAppNamespace.messageCounter= (function(){

    var privateState = 0;

    var incrementCount = function () {
        privateState += 1;
    };

    return function (message) {
        incrementCount();
        //TODO something with the message! 
    }
})();

To, co tutaj robimy, to przypisywanie funkcji licznika komunikatów do zmiennej w naszej aplikacji. Jest to funkcja, która zwraca funkcję, którą natychmiast wykonujemy .

Koncepcje

Myślę, że warto pomyśleć o górnej linii w SomeComponent jako o przestrzeni nazw, w której coś deklarujesz. Jedynym zastrzeżeniem jest to, że wszystkie przestrzenie nazw muszą najpierw pojawić się w jakimś innym pliku - są to po prostu obiekty zakorzenione w naszej zmiennej aplikacji.

W tej chwili wykonałem tylko drobne kroki (refaktoryzuję normalny skrypt javascript z aplikacji extjs, aby móc go przetestować), ale wydaje się to całkiem miłe, ponieważ możesz zdefiniować małe jednostki funkcjonalne, unikając grzęzawiska tego ” .

Możesz również użyć tego stylu do definiowania konstruktorów, zwracając funkcję, która zwraca obiekt z kolekcją funkcji i nie wywołując jej od razu.


6

Tutaj https://toddmotto.com/mastering-the-module-pattern znajdziesz dokładnie wyjaśniony wzór. Dodam, że drugą rzeczą dotyczącą modułowego JavaScript jest struktura kodu w wielu plikach. Wiele osób może ci doradzić, abyś skorzystał z AMD, ale z doświadczenia mogę powiedzieć, że w pewnym momencie skończy się wolna odpowiedź strony z powodu wielu żądań HTTP. Wyjściem jest wstępna kompilacja modułów JavaScript (po jednym na plik) do jednego pliku zgodnie ze standardem CommonJS. Spójrz na próbki tutaj http://dsheiko.github.io/cjsc/


Wszystkie implementacje AMD zapewniają również prekompilację w jednym pliku.
I-Lin Kuo

1
To prawda, ale wynikowy zoptymalizowany plik wymaga biblioteki ładującej (po prostu sprawdziliśmy ją ponownie za pomocą r.js v2.1.14), która zwykle jest dość ciężka. Gdy tylko skompilujemy kod, nie potrzebujemy rozwiązywania zależności ładowanych asynchronicznie, nie potrzebujemy tej biblioteki. Wystarczy pomyśleć: opakowujemy moduły w AMD, co oznacza asynchroniczne. ładowanie, a następnie skompiluj je w jednym pliku (bez oddzielnego ładowania), ale załaduj całą bibliotekę, aby je rozwiązać (co jest teraz zbędne). Nie wydaje mi się to optymalnym sposobem. Dlaczego w ogóle AMD, skoro nie ładujemy asynchronicznie?
Dmitry Sheiko

almond.js zapewnia mniejszą wagę programu ładującego dla gotowego kodu produkcyjnego niż RequireJS, ale porównując, korzyści wynikające z niewykonania pojedynczego żądania http znacznie przewyższają koszt dodania kodu modułu ładującego do modułu, więc chociaż jest mniej optymalny, na znacznie mniejszą skalę. Moim zdaniem pytanie powinno zostać odwrócone - po co zakładać synchroniczność, gdy przeglądarka nie jest? Właściwie jestem zdania, że obie RequireJS i CommonJS powinien mieć wbudowany realizację obietnicy.
I-Lin Kuo

Oba formaty są prawidłowymi ścieżkami do CommonJS Modules / 2.0 i zapewniają taką samą skalowalność. Jak dla mnie - radzenie sobie z CJS Modules / 1.1 (to mam na myśli przez CommonJS) jest dużo łatwiejsze, kod wygląda na bardziej przejrzysty.
Dmitry Sheiko

Spotkałem takie zalety AMD jak: * potrafi załadować więcej niż tylko pliki JavaScript; * aliasy ścieżek; Cóż, CommonJS Compiler rozwiązuje te problemy - ładuje zależności inne niż JavaScipt / JSON jako dane i może być wyposażony w konfigurację kompilacji (w tym aliasy). Jedyna wada, że ​​wymaga budowania. Ale obecnie każdy buduje projekt dla preprocesorów CSS. Więc chodzi tylko o dodanie dodatkowego zadania dla Grunt / Gulp ...
Dmitry Sheiko

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.