Powszechnie akceptowane najlepsze praktyki dotyczące organizacji kodu w JavaScript [zamknięte]

561

Ponieważ frameworki JavaScript, takie jak jQuery, sprawiają, że aplikacje internetowe po stronie klienta są bogatsze i bardziej funkcjonalne, zaczęłam zauważać jeden problem ...

Jak na świecie utrzymujesz to w porządku?

  • Umieścić wszystkich swoich handlerów w jednym miejscu i pisać funkcje dla wszystkich wydarzeń?
  • Utworzyć funkcję / klasy, aby zawinąć całą swoją funkcjonalność?
  • Pisz jak szalony i masz tylko nadzieję, że się uda?
  • Zrezygnować i dostać nową karierę?

Wspominam o jQuery, ale tak naprawdę jest to ogólnie dowolny kod JavaScript. Zauważyłem, że kiedy linie po liniach zaczynają się układać w stosy, trudniej jest zarządzać plikami skryptów lub znajdować to, czego szukasz. Prawdopodobnie największym problemem, jaki znalazłem, jest to, że istnieje tak wiele sposobów na zrobienie tego samego, trudno jest ustalić, który z nich jest obecnie powszechnie akceptowaną najlepszą praktyką.

Czy istnieją jakieś ogólne zalecenia dotyczące najlepszego sposobu, aby pliki .js były tak ładne i schludne, jak reszta aplikacji? Czy to tylko kwestia IDE? Czy jest tam lepsza opcja?


EDYTOWAĆ

To pytanie miało dotyczyć raczej organizacji kodu, a nie organizacji plików. Istnieje kilka naprawdę dobrych przykładów łączenia plików lub dzielenia treści.

Moje pytanie brzmi: jaki jest obecnie powszechnie akceptowany sposób najlepszych praktyk w celu uporządkowania twojego kodu? Jaka jest twoja droga, a nawet zalecany sposób interakcji z elementami strony i tworzenia kodu do ponownego użycia, który nie powoduje konfliktów?

Niektóre osoby wymieniły przestrzenie nazw, co jest dobrym pomysłem. Jakie są inne sposoby, w szczególności zajmowanie się elementami na stronie oraz utrzymanie porządku i porządku w kodzie?

Hugoware
źródło
ktoś, kto faktycznie poświęcił czas na mówienie o samej organizacji kodu, a nie „tylko”, jakiego narzędzia używa do łączenia i kompresji swoich plików JS: stackoverflow.com/questions/16736483/…
Adrien Be

Odpowiedzi:

183

Byłoby o wiele ładniej, gdyby javascript miał wbudowane przestrzenie nazw, ale uważam, że organizowanie rzeczy takich jak Dustin Diaz tutaj bardzo mi pomaga.

var DED = (function() {

    var private_var;

    function private_method()
    {
        // do stuff here
    }

    return {
        method_1 : function()
            {
                // do stuff here
            },
        method_2 : function()
            {
                // do stuff here
            }
    };
})();

W oddzielnych plikach umieszczam różne „przestrzenie nazw”, a czasem poszczególne klasy. Zwykle zaczynam od jednego pliku, a gdy klasa lub przestrzeń nazw stają się wystarczająco duże, aby to uzasadnić, dzielę je na własny plik. Użycie narzędzia do łączenia wszystkich plików do produkcji jest również doskonałym pomysłem.

polarbear
źródło
24
Zwykle nazywam to „drogą Crockforda”. +1 ode mnie
Matt Briggs,
4
Możesz nawet pójść nieco dalej. Zobacz ten link: wait-till-i.com/2007/08/22/…
MKroehnert
4
@MattBriggs inaczej nazywany jest module patterni jest oparty na IIFE pattern.
Adrien Be
Nie musisz w jakiś sposób eksportować klas? Jak powstaje obiekt z zewnątrz takiego modułu? A może powinna istnieć metoda createNewSomething()w obiekcie zwracanym, aby tworzenie obiektu odbywało się wyłącznie w module? Hm ... Spodziewałbym się, że klasy (konstruktory) są widoczne z zewnątrz.
robsch
@robsch Jego przykład nie przyjmuje żadnych parametrów, ale większość by. Zobacz mój przykład tutaj, jak to zwykle się robi (TypeScript, ale 99% to samo): repl.it/@fatso83/Module-Pattern-in-TypeScript
oligofren
88

Staram się unikać dołączania jakiegokolwiek kodu JavaScript do kodu HTML. Cały kod jest enkapsulowany w klasy, a każda klasa znajduje się we własnym pliku. Do programowania mam osobne tagi <script>, które zawierają każdy plik js, ale są one łączone w jeden większy pakiet do produkcji, aby zmniejszyć obciążenie żądaniami HTTP.

Zazwyczaj będę mieć jeden „główny” plik js dla każdej aplikacji. Więc gdybym pisał aplikację „ankietową”, miałbym plik js o nazwie „survey.js”. Zawierałby punkt wejścia do kodu jQuery. Podczas tworzenia instancji tworzę referencje jQuery, a następnie przekazuję je do moich obiektów jako parametry. Oznacza to, że klasy javascript są „czyste” i nie zawierają żadnych odniesień do identyfikatorów CSS ani nazw klas.

// file: survey.js
$(document).ready(function() {
  var jS = $('#surveycontainer');
  var jB = $('#dimscreencontainer');
  var d = new DimScreen({container: jB});
  var s = new Survey({container: jS, DimScreen: d});
  s.show();
});

Uważam też, że konwencja nazewnictwa jest ważna dla czytelności. Na przykład: wstawiam „j” do wszystkich instancji jQuery.

W powyższym przykładzie istnieje klasa o nazwie DimScreen. (Załóżmy, że to przyciemnia ekran i wyskakuje okno ostrzeżenia.) Potrzebuje elementu div, który można powiększyć, aby zakrył ekran, a następnie dodać pole ostrzeżenia, więc przekazuję obiekt jQuery. jQuery ma koncepcję wtyczek, ale wydawało się to ograniczające (np. instancje nie są trwałe i nie można uzyskać do nich dostępu) bez prawdziwej korzyści. Zatem klasa DimScreen byłaby standardową klasą javascript, która akurat używa jQuery.

// file: dimscreen.js
function DimScreen(opts) { 
   this.jB = opts.container;
   // ...
}; // need the semi-colon for minimizing!


DimScreen.prototype.draw = function(msg) {
  var me = this;
  me.jB.addClass('fullscreen').append('<div>'+msg+'</div>');
  //...
};

Korzystając z tego podejścia, zbudowałem dość złożone aplikacje.

Jason Moore
źródło
15
Uważam, że używanie $jako przedrostka nazwy zmiennej jest bardziej powszechną praktyką, ale mogę się mylić. Tak więc, $s = $('...')zamiast jS = $('...'), po prostu kwestia preferencji chyba. Ciekawe, ponieważ węgierski zapis jest uważany za zapach kodu. To dziwne, jak różne są niektóre moje konwencje / preferencje kodu JavaScript od moich konwencji kodowania C # / Java.
jamiebarrow
9
@jamie W tym przypadku nie jest to zapach kodu, to jeden z niewielu przypadków, w których węgierski jest dobry . Może chcesz przeczytać ten .
Dan Abramov
3
@DanAbramov dziękuję za link. Naprawdę muszę czytać wszystkie blogi Joela, on tak dobrze wszystko wyjaśnia. Zdecydowanie zasługuje na sławę / reputację, którą ma. Będę się odnosił Systems Hungarianjako zapach kodu i Apps Hungarianodtąd jako praktyka :)
jamiebarrow,
Wydaje mi się, że w świecie C # może to być świetny artykuł promujący użycie var, teraz, gdy o tym myślę. Większość argumentów przeciwko używaniu varjest tam, gdzie nie jesteś pewien „rodzaju” tego, co jest zwracane, ale myślę, że argument raczej powinien być przeciwko nie znać „klasy” tego, co jest zwracane. Jeśli korzystasz z aplikacji węgierskiej, nie powinieneś mieć tego problemu, to ... interesujące.
jamiebarrow 13.10.11
3
@Marnen: Rozumiem twój punkt widzenia, ale nie jest bezużyteczny jako przewodnik dla programisty. Prefiks $ przypomina mi, co to jest, gdy czytam mój kod później, a tym samym pomaga w szybszym zrozumieniu.
Sean
39

Możesz podzielić swoje skrypty na osobne pliki w celu opracowania, a następnie utworzyć wersję „release”, w której je wszystkie razem napychasz i uruchamiasz na nich Kompresor YUI lub coś podobnego.

Greg
źródło
Czasami są niepotrzebne skrypty javascript. Wysyłanie ich do klienta jest niepotrzebne. Myślę, że przesyła tylko to, co jest potrzebne. Oczywiście w przypadku aplikacji internetowej, która jest używana przez cały dzień, takiej jak aplikacja intranetowa, lepszym rozwiązaniem może być wysłanie całej partii naraz, przy ładowaniu pierwszej strony.
DOK
2
Kompilacja @DOK powinna obejmować usunięcie nieużywanych rzeczy.
aehlke,
Istnieje również koncepcja leniwego ładowania w celu zmniejszenia zapotrzebowania na przepustowość, polegającego na załadowaniu strony początkowej, a następnie wykonaniu asynchronicznego ładowania wymaganych plików skryptów (jak wspomniano w innych odpowiedziach na to pytanie). Chociaż może to wymagać więcej wniosków i może być mniej przydatne. @DOK, jeśli JS jest buforowany, jedno średnie żądanie może być lepsze niż kilka małych.
jamiebarrow,
27

Zainspirowany wcześniejszymi postami, zrobiłem kopię katalogu Rakefile i katalogów dostawców dystrybuowanych wraz z WysiHat (RTE wspomnianym przez dziennik zmian) i wprowadziłem kilka modyfikacji w celu włączenia sprawdzania kodu za pomocą JSLint i minimalizacji za pomocą YUI Compressor .

Chodzi o to, aby użyć Sprockets (z WysiHat) do scalenia wielu skryptów JavaScript w jeden plik, sprawdzenia składni scalonego pliku za pomocą JSLint i zminimalizowania go za pomocą YUI Compressor przed dystrybucją.

Wymagania wstępne

  • Środowisko wykonawcze Java
  • klejnot ruby ​​i prowizji
  • Powinieneś wiedzieć, jak umieścić JAR w Classpath

Teraz zrób

  1. Pobieranie Rhino i umieść JAR („js.jar”) w ścieżce klasy
  2. Pobieranie kompresor YUI i umieść JAR (build / yuicompressor-xyz.jar) w ścieżce klasy
  3. Pobieranie WysiHat i skopiuj katalog „vendor” do katalogu głównego projektu JavaScript
  4. Pobierz JSLint dla Rhino i umieść go w katalogu „vendor”

Teraz utwórz plik o nazwie „Rakefile” w katalogu głównym projektu JavaScript i dodaj do niego następującą treść:

require 'rake'

ROOT            = File.expand_path(File.dirname(__FILE__))
OUTPUT_MERGED   = "final.js"
OUTPUT_MINIFIED = "final.min.js"

task :default => :check

desc "Merges the JavaScript sources."
task :merge do
  require File.join(ROOT, "vendor", "sprockets")

  environment  = Sprockets::Environment.new(".")
  preprocessor = Sprockets::Preprocessor.new(environment)

  %w(main.js).each do |filename|
    pathname = environment.find(filename)
    preprocessor.require(pathname.source_file)
  end

  output = preprocessor.output_file
  File.open(File.join(ROOT, OUTPUT_MERGED), 'w') { |f| f.write(output) }
end

desc "Check the JavaScript source with JSLint."
task :check => [:merge] do
  jslint_path = File.join(ROOT, "vendor", "jslint.js")

  sh 'java', 'org.mozilla.javascript.tools.shell.Main',
    jslint_path, OUTPUT_MERGED
end

desc "Minifies the JavaScript source."
task :minify => [:merge] do
  sh 'java', 'com.yahoo.platform.yui.compressor.Bootstrap', '-v',
    OUTPUT_MERGED, '-o', OUTPUT_MINIFIED
end

Jeśli wszystko wykonałeś poprawnie, powinieneś być w stanie użyć następujących poleceń w konsoli:

  • rake merge - aby połączyć różne pliki JavaScript w jeden
  • rake check- aby sprawdzić składnię kodu (jest to zadanie domyślne , więc możesz po prostu pisać rake)
  • rake minify - w celu przygotowania zminimalizowanej wersji kodu JS

Po scaleniu źródła

Za pomocą Sprockets, preprocesora JavaScript, możesz dołączyć (lub require) inne pliki JavaScript. Użyj następującej składni, aby dołączyć inne skrypty z pliku początkowego (o nazwie „main.js”, ale możesz to zmienić w pliku Rakefile):

(function() {
//= require "subdir/jsfile.js"
//= require "anotherfile.js"

    // some code that depends on included files
    // note that all included files can be in the same private scope
})();

I wtedy...

Spójrz na Rakefile dostarczony z WysiHat, aby skonfigurować automatyczne testowanie jednostek. Fajne rzeczy :)

A teraz odpowiedź

To nie odpowiada zbyt dobrze na pierwotne pytanie. Wiem i przykro mi z tego powodu, ale opublikowałem to tutaj, ponieważ mam nadzieję, że może być przydatne dla kogoś innego, aby zorganizować swój bałagan.

Moje podejście do problemu polega na tym, aby wykonać jak najwięcej modelowania obiektowego i rozdzielić implementacje na różne pliki. W takim przypadku przewodnicy powinni być jak najkrótsi. Przykład z Listsingletonem jest również fajny.

I przestrzenie nazw ... cóż, można je naśladować głębszą strukturą obiektu.

if (typeof org === 'undefined') {
    var org = {};
}

if (!org.hasOwnProperty('example')) {
    org.example = {};
}

org.example.AnotherObject = function () {
    // constructor body
};

Nie jestem wielkim fanem imitacji, ale może to być pomocne, jeśli masz wiele obiektów, które chciałbyś przenieść poza globalny zasięg.

Damir Zekić
źródło
18

Organizacja kodu wymaga przyjęcia konwencji i standardów dokumentacji:
1. Kod przestrzeni nazw dla pliku fizycznego;

Exc = {};


2. Klasy grup w tych javascript przestrzeni nazw;
3. Ustaw prototypy lub powiązane funkcje lub klasy do reprezentowania rzeczywistych obiektów;

Exc = {};
Exc.ui = {};
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};
Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    ...
};


4. Ustaw konwencje, aby poprawić kod. Na przykład zgrupuj wszystkie wewnętrzne funkcje lub metody w atrybucie klasy typu obiektu.

Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    this.internal = {
        widthEstimates: function (tips) {
            ...
        }
        formatTips: function () {
            ...
        }
    };
    ...
};


5. Wykonaj dokumentację przestrzeni nazw, klas, metod i zmiennych. W razie potrzeby omów także część kodu (niektóre FI i Fors, zwykle implementują ważną logikę kodu).

/**
  * Namespace <i> Example </i> created to group other namespaces of the "Example".  
  */
Exc = {};
/**
  * Namespace <i> ui </i> created with the aim of grouping namespaces user interface.
  */
Exc.ui = {};

/**
  * Class <i> maskdInput </i> used to add an input HTML formatting capabilities and validation of data and information.
  * @ Param {String} mask - mask validation of input data.
  */
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};

/**
  * Class <i> domTips </i> used to add an HTML element the ability to present tips and information about its function or rule input etc..
  * @ Param {String} id - id of the HTML element.
  * @ Param {String} tips - tips on the element that will appear when the mouse is over the element whose identifier is id <i> </i>.
  */
  Exc.ui.domTips = function (id, tips) {
    this.domID = id;
    this.tips = tips;
    ...
};


To tylko kilka wskazówek, ale to bardzo pomogło w organizacji kodu. Pamiętaj, że musisz mieć dyscyplinę, aby odnieść sukces!

Nery Jr
źródło
13

Przestrzeganie dobrych zasad projektowania OO i wzorców projektowych znacznie ułatwia tworzenie i zrozumienie kodu. Ale jedną z najlepszych rzeczy, które ostatnio odkryłem, są sygnały i automaty, czyli publikowanie / subskrybowanie. Zajrzyj na http://markdotmeyer.blogspot.com/2008/09/jquery-publish-subscribe.html, aby uzyskać prostą implementację jQuery.

Pomysł jest dobrze wykorzystywany w innych językach do tworzenia GUI. Kiedy coś znaczącego dzieje się gdzieś w kodzie, publikujesz globalne syntetyczne zdarzenie, które inne metody w innych obiektach mogą subskrybować. Zapewnia to doskonałą separację obiektów.

Myślę, że Dojo (i Prototyp?) Mają wbudowaną wersję tej techniki.

zobacz także Co to są sygnały i gniazda?

meouw
źródło
Zrobiłem to w jQuery. JS ma wbudowany model zdarzeń, więc tak naprawdę nie potrzebujesz dużego wsparcia dla frameworków.
Marnen Laibow-Koser
12

W poprzednim zadaniu mogłem z powodzeniem zastosować wzorzec modułu JavaScript do aplikacji Ext JS. Zapewniło to prosty sposób na stworzenie ładnie zamkniętego kodu.

Alan
źródło
11

Dojo miał system modułowy od pierwszego dnia. W rzeczywistości jest uważany za kamień węgielny Dojo, kleju, który trzyma to wszystko razem:

Za pomocą modułów Dojo osiąga następujące cele:

  • Przestrzenie nazw dla kodu Dojo i kodu niestandardowego (dojo.declare() ) - nie zanieczyszczają globalnej przestrzeni, współistnieją z innymi bibliotekami i nie rozpoznają kodu Dojo użytkownika.
  • Ładowanie modułów synchronicznie lub asynchronicznie według nazwy (dojo.require() ).
  • Niestandardowe kompilacje poprzez analizę zależności modułów w celu utworzenia pojedynczego pliku lub grupy współzależnych plików (tak zwanych warstw) w celu uwzględnienia tylko tego, czego potrzebuje Twoja aplikacja internetowa. Kompilacje niestandardowe mogą również obejmować moduły Dojo i moduły dostarczone przez klienta.
  • Przejrzysty dostęp oparty na CDN do Dojo i kodu użytkownika. Zarówno AOL, jak i Google noszą Dojo w ten sposób, ale niektórzy klienci robią to również w przypadku niestandardowych aplikacji internetowych.
Eugene Lazutkin
źródło
9

Sprawdź JavciptMVC .

Możesz :

  • podziel swój kod na warstwy modelu, widoku i kontrolera.

  • skompresuj cały kod do jednego pliku produkcyjnego

  • automatyczne generowanie kodu

  • tworzyć i uruchamiać testy jednostkowe

  • i wiele więcej...

Najlepsze jest to, że korzysta z jQuery, więc możesz również skorzystać z innych wtyczek jQuery.

andyuk
źródło
Tak, użyłem jmvc i jest całkiem niezły
doktorzy
9

Mój szef wciąż mówi o czasach, kiedy pisali kod modułowy (język C) i narzeka na to, jak kiepski jest obecnie kod! Mówi się, że programiści mogą pisać asemblery w dowolnym frameworku. Zawsze istnieje strategia pokonania organizacji kodu. Podstawowy problem dotyczy facetów, którzy traktują skrypt Java jako zabawkę i nigdy nie próbują się go nauczyć.

W moim przypadku piszę pliki js na podstawie motywu interfejsu użytkownika lub ekranu aplikacji za pomocą odpowiedniej init_screen (). Stosując odpowiednią konwencję nazewnictwa id, upewniam się, że nie ma konfliktów przestrzeni nazw na poziomie elementu głównego. W dyskretnej funkcji window.load () wiążę rzeczy na podstawie identyfikatora najwyższego poziomu.

Ściśle używam zamknięć i wzorców skryptów Java, aby ukryć wszystkie prywatne metody. Po wykonaniu tej czynności nigdy nie stanął przed problemem sprzecznych właściwości / definicji funkcji / definicji zmiennych. Jednak podczas pracy z zespołem często trudno jest wyegzekwować ten sam rygor.

questzen
źródło
9

Dziwi mnie, że nikt nie wspominał o platformach MVC. Korzystam z Backbone.js do modularyzacji i oddzielania kodu, a to było nieocenione.

Istnieje wiele tego rodzaju ram, a większość z nich jest również bardzo mała. Moja osobista opinia jest taka, że ​​jeśli zamierzasz pisać więcej niż tylko kilka wierszy jQuery dla efektownych interfejsów użytkownika lub potrzebujesz bogatej aplikacji Ajax, środowisko MVC znacznie ułatwi ci życie.

Chetan
źródło
8

„Pisz jak szalony i po prostu masz nadzieję, że się uda”. Widziałem taki projekt, który został opracowany i obsługiwany przez zaledwie 2 programistów, ogromną aplikację z dużą ilością kodu javascript. Oprócz tego istniały różne skróty do każdej możliwej funkcji jquery, o której można pomyśleć. Zasugerowałem, aby zorganizowali kod jako wtyczki, ponieważ jest to równoważny jquery klasy, modułu, przestrzeni nazw ... i całego wszechświata. Ale stało się znacznie gorzej, teraz zaczęli pisać wtyczki zastępujące każdą kombinację 3 linii kodu użytych w projekcie. Osobiście uważam, że jQuery jest diabłem i nie powinien być używany w projektach z dużą ilością javascript, ponieważ zachęca cię do lenistwa i nie myślenia o organizowaniu kodu w jakikolwiek sposób. Wolę czytać 100 wierszy javascript niż jeden wiersz z 40 połączonymi funkcjami jQuery (I ' nie żartuję). Wbrew powszechnemu przekonaniu bardzo łatwo jest zorganizować kod javascript w ekwiwalentach przestrzeni nazw i klas. Tak właśnie robią YUI i Dojo. Jeśli chcesz, możesz łatwo rzucić własne. Uważam, że podejście YUI jest znacznie lepsze i wydajniejsze. Ale zwykle potrzebujesz ładnego edytora z obsługą fragmentów, aby zrekompensować konwencje nazewnictwa YUI, jeśli chcesz napisać cokolwiek przydatnego.

Wasil
źródło
3
Zgadzam się z tobą w sprawie naprawdę długich, powiązanych łańcuchowo poleceń, ale jedną z najlepszych części jQuery jest to, że nie pozwala JavaScriptowi na kodowanie HTML. Możesz skonfigurować moduły obsługi zdarzeń dla wszystkich swoich elementów bez „potrzeby” dodawania identyfikatorów lub zdarzeń <cokolwiek> w swoich elementach. Jak zawsze, nadmierne użycie jakiegokolwiek narzędzia jest złe ...
Hugoware,
Pracowałem nad dużymi, dobrze zorganizowanymi projektami w jQuery. Nie wiem, dlaczego uważasz, że przeszkadza to w organizacji.
Marnen Laibow-Koser
7

Tworzę singletony dla każdej rzeczy, której naprawdę nie muszę tworzyć kilka razy na ekranie, zajęcia dla wszystkiego innego. Wszystkie są umieszczone w tej samej przestrzeni nazw w tym samym pliku. Wszystko zostało skomentowane i zaprojektowane przy użyciu diagramów stanów UML. Kod javascript jest wolny od html, więc nie ma wbudowanego javascript, a ja zwykle używam jquery, aby zminimalizować problemy między przeglądarkami.

Nikola Stjelja
źródło
3
dobry komentarz to KLUCZ - cieszę się, że to powiedziałeś, więc nie musiałem. Dodałbym spójne konwencje nazewnictwa, pewnego rodzaju łatwą do zrozumienia strategię organizacji zmiennych i wzmacniaczy; funkcje i, jak wspomniałeś, rozsądne użycie klas w porównaniu do singletonów.
matt lohkamp,
Nie. Jeśli potrzebujesz komentarzy, twój kod jest na ogół niewystarczająco czytelny. Staraj się pisać kod, który nie wymaga komentarzy.
Marnen Laibow-Koser
Ponadto, jeśli potrzebujesz UML i diagramów stanów, prawdopodobnie oznacza to, że twoja architektura nie jest wystarczająco czytelna z kodu. Downvoting.
Marnen Laibow-Koser
1
@Marnen Dobrze napisane projekty zawierają komentarze opisujące DLACZEGO, niekoniecznie CO. Kod już opisuje CO, ale często trzeba coś opisać DLACZEGO. Upvoting.
Cypher
@Cypher Dobrze napisane projekty mają wystarczająco wyraźny kod, że zwykle można powiedzieć „dlaczego”, a nie tylko „co”. Nie ufałbym komentarzowi, który powiedziałby mi „dlaczego”, ponieważ nie mam gwarancji, że jest zsynchronizowany z kodem. Niech sam koduje dokument.
Marnen Laibow-Koser
6

W moim ostatnim projekcie - Viajeros.com - użyłem kombinacji kilku technik. Nie wiedziałbym, jak zorganizować aplikację internetową - Viajeros to portal społecznościowy dla podróżników z dobrze zdefiniowanymi sekcjami, więc łatwo jest oddzielić kod dla każdego obszaru.

Używam symulacji przestrzeni nazw i leniwego ładowania modułów zgodnie z sekcją serwisu. Na każdej stronie ładuję deklaruję obiekt „vjr” i zawsze ładuję do niego zestaw typowych funkcji (vjr.base.js). Następnie każda strona HTML decyduje, które moduły potrzebują w prosty sposób:

vjr.Required = ["vjr.gallery", "vjr.comments", "vjr.favorites"];

Vjr.base.js pobiera każdy gzip z serwera i wykonuje je.

vjr.include(vjr.Required);
vjr.include = function(moduleList) {
  if (!moduleList) return false;
  for (var i = 0; i < moduleList.length; i++) {
    if (moduleList[i]) {
      $.ajax({
        type: "GET", url: vjr.module2fileName(moduleList[i]), dataType: "script"
      });
    }
  }
};

Każdy „moduł” ma następującą strukturę:

vjr.comments = {}

vjr.comments.submitComment = function() { // do stuff }
vjr.comments.validateComment = function() { // do stuff }

// Handlers
vjr.comments.setUpUI = function() {
    // Assign handlers to screen elements
}

vjr.comments.init = function () {
  // initialize stuff
    vjr.comments.setUpUI();
}

$(document).ready(vjr.comments.init);

Biorąc pod uwagę moją ograniczoną wiedzę na temat Javascript, wiem, że muszą istnieć lepsze sposoby na zarządzanie tym, ale do tej pory działa świetnie dla nas.

Danita
źródło
6

Porządkowanie kodu w sposób oparty na Jquery NameSpace może wyglądać następująco ... i nie będzie kolidować z innymi interfejsami API JavaScript, takimi jak Prototype, Ext.

<script src="jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script type="text/javascript">

var AcmeJQ = jQuery.noConflict(true);
var Acme = {fn: function(){}};

(function($){

    Acme.sayHi = function()
    {
        console.log('Hello');
    };

    Acme.sayBye = function()
    {
        console.log('Good Bye');
    };
})(AcmeJQ);

// Usage
//          Acme.sayHi();
// or
// <a href="#" onclick="Acme.sayHi();">Say Hello</a>


</script>

Mam nadzieję że to pomoże.

Darryl
źródło
Uderza mnie to jako niewielki ładunek. jQuery.fnjest wskaźnikiem do jQuery.prototype, ponieważ $()faktycznie zwraca nową instancję funkcji konstruktora jQuery. Dodanie „wtyczki” do jQuery oznacza po prostu rozszerzenie jego prototypu. Ale to, co robisz, nie jest tym, a istnieją czystsze sposoby na osiągnięcie tego samego.
Adam Lassek
Wierzę, że po prostu tworzy funkcje statyczne. Pamiętam, jak widziałem w dokumentach jQuery'ego, że ten sposób deklarowania funkcji statycznych jest dopuszczalny
Alex Heyd
6

Dobra zasada OO + MVC zdecydowanie przeszedłaby długą drogę do zarządzania złożoną aplikacją javascript.

Zasadniczo organizuję moją aplikację i skrypt javascript zgodnie z poniższym znanym projektem (który istnieje od czasów programowania na pulpicie do wersji Web 2.0)

JS OO i MVC

Opis wartości liczbowych na obrazie:

  1. Widżety przedstawiające widoki mojej aplikacji. Powinno to być rozszerzalne i starannie wyodrębnione, co powoduje dobrą separację, którą MVC stara się osiągnąć, zamiast przekształcania mojego widgetu w kod spaghetti (odpowiednik w aplikacji internetowej polegającej na umieszczaniu dużego bloku Javascript bezpośrednio w HTML). Każdy widżet komunikuje się za pośrednictwem innych, nasłuchując zdarzenia generowanego przez inne widżety, zmniejszając w ten sposób silne sprzężenie widżetów, które może prowadzić do niemożliwego do zarządzania kodu (pamiętasz dzień dodawania kliknięcia wszędzie, wskazując globalne funkcje w znaczniku skryptu? Urgh ...)
  2. Modele obiektowe reprezentujące dane, które chcę wypełnić w widżetach, i przesyłane tam iz powrotem na serwer. Dzięki enkapsulacji danych do modelu aplikacja staje się agnostyką formatu danych. Na przykład: podczas gdy oczywiście w JavaScript, te modele obiektowe są w większości serializowane i deserializowane do JSON, jeśli w jakiś sposób serwer używa XML do komunikacji, wszystko co muszę zmienić to zmienić warstwę serializacji / deserializacji i niekoniecznie musi zmienić wszystkie klasy widżetów .
  3. Klasy kontrolerów, które zarządzają logiką biznesową i komunikacją z serwerem + od czasu do czasu buforują warstwę. Ta warstwa kontroluje protokół komunikacyjny do serwera i umieszcza niezbędne dane w modelach obiektowych
  4. Klasy są starannie zapakowane w odpowiadające im przestrzenie nazw. Jestem pewien, że wszyscy wiemy, jak nieprzyjemna globalna przestrzeń nazw może być w JavaScript.

W przeszłości dzieliłem pliki na własne js i stosowałem powszechną praktykę do tworzenia zasad OO w JavaScript. Problem, który wkrótce odkryłem, że istnieje wiele sposobów pisania JS OO i niekoniecznie wszyscy członkowie zespołu mają takie samo podejście. W miarę powiększania się zespołu (w moim przypadku ponad 15 osób) komplikuje się to, ponieważ nie ma standardowego podejścia do JavaScript zorientowanego obiektowo. Jednocześnie nie chcę pisać własnego frameworka i powtarzać niektórych prac, które jestem pewien, że mądrzejsi ludzie, niż to rozwiązałem.

jQuery jest niesamowicie fajny jak JavaScript Framework i uwielbiam go, jednak wraz ze wzrostem projektu wyraźnie potrzebuję dodatkowej struktury dla mojej aplikacji internetowej, szczególnie w celu ułatwienia standaryzacji praktyki OO. Dla mnie po kilku eksperymentach stwierdzam, że infrastruktura YUI3 Base and Widget ( http://yuilibrary.com/yui/docs/widget/ and http://yuilibrary.com/yui/docs/base/index.html ) zapewnia infrastrukturę dokładnie to, czego potrzebuję. Kilka powodów, dla których ich używam.

  1. Zapewnia obsługę przestrzeni nazw. Prawdziwa potrzeba OO i porządnej organizacji twojego kodu
  2. Obsługuje pojęcie klas i obiektów
  3. Daje to standaryzowany sposób dodawania zmiennych instancji do twojej klasy
  4. Starannie wspiera rozszerzenie klasy
  5. Zapewnia konstruktor i destruktor
  6. Zapewnia renderowanie i wiązanie zdarzeń
  7. Ma podstawową strukturę widgetów
  8. Każdy widżet może teraz komunikować się ze sobą przy użyciu standardowego modelu opartego na zdarzeniach
  9. Co najważniejsze, daje wszystkim inżynierom standard OO dla rozwoju Javascript

W przeciwieństwie do wielu poglądów, niekoniecznie muszę wybierać między jQuery i YUI3. Ci dwaj mogą pokojowo współistnieć. Podczas gdy YUI3 zapewnia niezbędny szablon OO dla mojej złożonej aplikacji internetowej, jQuery wciąż zapewnia mojemu zespołowi łatwą w użyciu JS Abstraction, którą wszyscy kochamy i znamy.

Korzystając z YUI3, udało mi się stworzyć wzorzec MVC, oddzielając klasy rozszerzające Bazę jako Model, klasy rozszerzające Widżet jako Widok, a poza tym masz klasy Kontrolera, które wykonują niezbędną logikę i wywołania po stronie serwera.

Widżet może komunikować się ze sobą za pomocą modelu opartego na zdarzeniu i nasłuchiwania zdarzenia oraz wykonywania niezbędnych zadań w oparciu o predefiniowany interfejs. Mówiąc wprost, przeniesienie struktury OO + MVC do JS to dla mnie przyjemność.

Tylko zrzeczenie się, nie pracuję dla Yahoo! i po prostu architekt, który próbuje poradzić sobie z tym samym zagadnieniem, jakie stawia oryginalne pytanie. Myślę, że jeśli ktokolwiek znajdzie równoważne środowisko OO, to też zadziała. Zasadniczo to pytanie dotyczy również innych technologii. Dzięki Bogu za wszystkich ludzi, którzy wymyślili Zasady OO + MVC, aby nasze dni programowania były łatwiejsze do zarządzania.

minutę
źródło
5

używam z zarządzania pakietami ( dojo.requirei dojo.provide) pakietu Dojo oraz systemu klas ( dojo.declarektóry pozwala również na proste wielokrotne dziedziczenie), aby modulować wszystkie moje klasy / widżety w osobne pliki. Daje to nie tylko porządek w kodzie, ale także pozwala leniwie / na czas ładować klasy / widżety.

Justin Johnson
źródło
3

Kilka dni temu chłopaki z 37Signals wydali kontrolę RTE z . Stworzyli bibliotekę, w której pakowane są pliki javascript za pomocą poleceń poprzedzających procesor.

Używam go od tego czasu, aby oddzielić moje pliki JS, a następnie scalić je jako jeden. W ten sposób mogę rozdzielić problemy, a na koniec mieć tylko jeden plik, który przechodzi przez potok (gzipped, nie mniej).

W swoich szablonach sprawdź, czy jesteś w trybie programistycznym, i dołącz osobne pliki, a jeśli są w produkcji, dołącz ostatni (który będziesz musiał sam „zbudować”).

dziennik zmian
źródło
1
getsprockets.org to bezpośredni link
Matt Gardner
3

Twórz fałszywe klasy i upewnij się, że wszystko, co można wrzucić do osobnej funkcji, która ma sens, jest zrobione. Pamiętaj także, aby dużo komentować, a nie pisać kod spagghetti, raczej zachowując to wszystko w sekcjach. Na przykład jakiś nonsensowny kod przedstawiający moje ideały. Oczywiście w prawdziwym życiu piszę także wiele bibliotek, które w zasadzie obejmują ich funkcjonalność.

$(function(){
    //Preload header images
    $('a.rollover').preload();

    //Create new datagrid
    var dGrid = datagrid.init({width: 5, url: 'datalist.txt', style: 'aero'});
});

var datagrid = {
    init: function(w, url, style){
        //Rendering code goes here for style / width
        //code etc

        //Fetch data in
        $.get(url, {}, function(data){
            data = data.split('\n');
            for(var i=0; i < data.length; i++){
                //fetching data
            }
        })
    },
    refresh: function(deep){
        //more functions etc.
    }
};
Dmitri Farkov
źródło
3

Użyj wzorców dziedziczenia, aby organizować duże aplikacje jQuery.

Chetan
źródło
Zaczynam go używać, nawet do bardzo małych / podstawowych rzeczy, a to naprawdę pomaga utrzymać kod w czystości i elastyczności. Warto używać nawet do prostych manipulacji JS po stronie klienta.
Chetan
To lubię i używam w moich aplikacjach.
Andreas
2

Myślę, że wiąże się to być może z DDD (Domain-Driven Design). Aplikacja, nad którą pracuję, chociaż nie ma formalnego interfejsu API, daje takie wskazówki za pomocą kodu po stronie serwera (nazwy klas / plików itp.). Uzbrojony w to stworzyłem obiekt najwyższego poziomu jako kontener dla całej domeny problemowej; następnie dodałem obszary nazw w razie potrzeby:

var App;
(function()
{
    App = new Domain( 'test' );

    function Domain( id )
    {
        this.id = id;
        this.echo = function echo( s )
        {
            alert( s );
        }
        return this;
    }
})();

// separate file
(function(Domain)
{
    Domain.Console = new Console();

    function Console()
    {
        this.Log = function Log( s )
        {
            console.log( s );
        }
        return this;
    }
})(App);

// implementation
App.Console.Log('foo');
rozpoznać
źródło
2

Do organizacji JavaScript używam następujących

  1. Folder dla wszystkich skryptów JavaScript
  2. Javascript na poziomie strony otrzymuje własny plik o tej samej nazwie. ProductDetail.aspx to ProductDetail.js
  3. Wewnątrz folderu javascript dla plików bibliotek mam folder lib
  4. Umieść powiązane funkcje biblioteki w folderze lib, którego chcesz używać w swojej aplikacji.
  5. Ajax jest jedynym javascript, który przenoszę poza folder javascript i dostaje własny folder. Następnie dodaję dwa podfoldery klient i serwer
  6. Folder klienta pobiera wszystkie pliki .js, a folder serwera pobiera wszystkie pliki po stronie serwera.
Jason Too Cool Webs
źródło
Ładne dla organizacji plików. Robię to za pomocą kodu. Ale w końcu kompiluję kod w ... powiedzmy dll. Potrzebujesz tego również w javascript, bo w końcu poprosisz o 15 plików js na stronę.
graffic
Nie ma nic złego w żądaniu 15 plików JS na stronę. Twoja przeglądarka i tak je zbuforuje na kolejne żądania.
Marnen Laibow-Koser
@ MarnenLaibow-Koser Jedyny problem z żądaniem 15 plików JS na stronie dotyczy liczby żądań HTTP obsługiwanych jednocześnie przez przeglądarkę. Zatem połączenie ich w jeden plik pozwala przeglądarce na żądanie innych niezbędnych plików w tym samym czasie.
iwasrobbed 11.10.11
To prawda, ale po kilku pierwszych działaniach będą one w pamięci podręcznej przeglądarki, więc nie będą wymagały połączeń HTTP.
Marnen Laibow-Koser
2

Używam tej małej rzeczy. Daje dyrektywę „włącz” dla szablonów JS i HTML. Całkowicie eliminuje bałagan.

https://github.com/gaperton/include.js/

$.include({
    html: "my_template.html" // include template from file...
})
.define( function( _ ){ // define module...
    _.exports = function widget( $this, a_data, a_events ){ // exporting function...
        _.html.renderTo( $this, a_data ); // which expands template inside of $this.

        $this.find( "#ok").click( a_events.on_click ); // throw event up to the caller...
        $this.find( "#refresh").click( function(){
            widget( $this, a_data, a_events ); // ...and update ourself. Yep, in that easy way.
        });
    }
});
gaperton
źródło
2

Możesz użyć jquery mx (używanego w javascriptMVC), który jest zestawem skryptów, które pozwalają na używanie modeli, widoków i kontrolerów. Użyłem go w projekcie i pomógł mi stworzyć ustrukturyzowany javascript, z minimalnymi rozmiarami skryptu ze względu na kompresję. To jest przykład kontrolera:

$.Controller.extend('Todos',{
  ".todo mouseover" : function( el, ev ) {
   el.css("backgroundColor","red")
  },
  ".todo mouseout" : function( el, ev ) {
   el.css("backgroundColor","")
  },
  ".create click" : function() {
   this.find("ol").append("<li class='todo'>New Todo</li>"); 
  }
})

new Todos($('#todos'));

Możesz także używać tylko strony kontrolnej jquerymx, jeśli nie jesteś zainteresowany widokiem i częściami modelu.

rolnn
źródło
1

Twoje pytanie nęka mnie pod koniec ubiegłego roku. Różnica - przekazanie kodu nowym programistom, którzy nigdy nie słyszeli o metodach prywatnych i publicznych. Musiałem zbudować coś prostego.

Efektem końcowym była mała (około 1 KB) platforma, która tłumaczy literały obiektów na jQuery. Składnia jest wizualnie łatwiejsza do skanowania, a jeśli twój plik js naprawdę rośnie, możesz pisać zapytania wielokrotnego użytku, aby znaleźć takie rzeczy, jak używane selektory, załadowane pliki, funkcje zależne itp.

Zamieszczanie tutaj małego frameworka jest niepraktyczne, więc napisałem post na blogu z przykładami (Moja pierwsza. To była przygoda!). Zapraszamy do obejrzenia.

Wszystkim innym, którzy mają kilka minut, aby to sprawdzić, bardzo dziękuję za opinie!

FireFox jest zalecany, ponieważ obsługuje toSource () dla przykładu zapytania obiektowego.

Twoje zdrowie!

Adam

Adam
źródło
0

Używam niestandardowego skryptu zainspirowanego zachowaniem Bena Nolana (niestety nie mogę już znaleźć obecnego linku do tego), aby przechowywać większość moich programów obsługi zdarzeń. Te procedury obsługi zdarzeń są wyzwalane na przykład przez elementy className lub Id. Przykład:

Behaviour.register({ 
    'a.delete-post': function(element) {
        element.observe('click', function(event) { ... });
    },

    'a.anotherlink': function(element) {
        element.observe('click', function(event) { ... });
    }

});

Lubię dołączać większość moich bibliotek Javascript w locie, z wyjątkiem tych, które zawierają globalne zachowanie. Używam do tego zastępczego programu pomocniczego headScript () Zend Framework , ale możesz również użyć javascript do ładowania innych skryptów w locie, na przykład za pomocą Ajile .

Aron Rotteveel
źródło
Czy tego właśnie szukałeś? koders.com/javascript/…
DOK
Tak, to jest to! :) Wydaje się, że kod za linkiem jest jednak nowszy niż wersja, którą zainspirowałem. Dzięki za twój wysiłek!
Aron Rotteveel,
0

Nie wspominasz, jaki jest twój język po stronie serwera. Lub, bardziej trafnie, z jakich ram korzystasz - jeśli w ogóle - po stronie serwera.

IME, organizuję rzeczy po stronie serwera i pozwalam, aby wszystko trzęsło się na stronie internetowej. Zadaniem frameworka jest uporządkowanie nie tylko JS, które każda strona musi załadować, ale także fragmentów JS, które działają z wygenerowanym znacznikiem. Takie fragmenty, których zwykle nie chcesz emitować więcej niż jeden raz - dlatego są abstrakcyjne w ramach, aby ten kod mógł zająć się tym problemem. :-)

W przypadku stron końcowych, które muszą emitować własne JS, zwykle stwierdzam, że w wygenerowanym znaczniku istnieje logiczna struktura. Taki zlokalizowany JS często można złożyć na początku i / lub na końcu takiej struktury.

Pamiętaj, że nic z tego nie zwalnia od pisania wydajnego JavaScript! :-)

staticsan
źródło
0

Leniwy Załaduj potrzebny kod na żądanie. Google robi coś takiego za pomocą swojego google.loader

Brig Lamoreaux
źródło