Общепринятые лучшие практики организации кода в JavaScript [закрыто]

561

Поскольку JavaScript-фреймворки, такие как jQuery, делают клиентские веб-приложения богаче и функциональнее, я начал замечать одну проблему ...

Как в мире вы держите это организованным?

  • Разместите все свои обработчики в одном месте и напишите функции для всех событий?
  • Создать функцию / классы, чтобы обернуть всю вашу функциональность?
  • Писать как сумасшедший и просто надеяться, что все получится лучше
  • Сдаться и начать новую карьеру?

Я упоминаю jQuery, но это вообще любой код JavaScript. Я обнаружил, что, когда строки за строками начинают накапливаться, становится сложнее управлять файлами сценариев или находить то, что вы ищете. Вполне возможно, что самые большие проблемы, которые я обнаружил, состоят в том, что существует множество способов сделать то же самое, и трудно понять, какой из них является общепринятым в настоящее время.

Есть ли общие рекомендации о том, как сохранить ваши файлы .js такими же красивыми и аккуратными, как и все остальное в вашем приложении? Или это просто вопрос IDE? Есть ли лучший вариант там?


РЕДАКТИРОВАТЬ

Этот вопрос предназначался скорее для организации кода, а не для организации файлов. Было несколько действительно хороших примеров слияния файлов или разделения контента.

Мой вопрос: каков на сегодняшний день общепринятый способ организации вашего кода? Каков ваш способ или даже рекомендуемый способ взаимодействия с элементами страницы и создания повторно используемого кода, который не конфликтует друг с другом?

Некоторые люди перечислили пространства имен, что является хорошей идеей. Каковы другие способы, более конкретно относящиеся к элементам на странице и поддерживающие упорядоченный и аккуратный код?

Hugoware
источник
кто-то, кто действительно нашел время, чтобы поговорить о самой организации кода, а не просто о том, какой инструмент он использует для объединения и сжатия своих файлов JS: stackoverflow.com/questions/16736483/…
Adrien Be

Ответы:

183

Было бы намного лучше, если бы в javascript были встроены пространства имен, но я обнаружил, что организация таких вещей, как Дастин Диаз, описанная здесь, мне очень помогает.

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

Я помещаю разные «пространства имен», а иногда и отдельные классы в отдельные файлы. Обычно я начинаю с одного файла и, когда класс или пространство имен становится достаточно большим, чтобы его оправдать, я разделяю его на собственный файл. Использование инструмента для объединения всех ваших файлов для производства также является отличной идеей.

polarbear
источник
24
Я обычно называю это «крокфордским путем». +1 от меня
Мэтт Бриггс
4
Вы даже можете пойти немного дальше. Смотрите эту ссылку: wait-till-i.com/2007/08/22/…
MKroehnert
4
@MattBriggs в противном случае называется module patternи он основан на IIFE pattern.
Adrien Be
Вам не нужно как-то экспортировать классы? Как объект создается снаружи такого модуля? Или должен быть метод createNewSomething()в возвращаемом объекте, чтобы создание объекта происходило исключительно внутри модуля? Хм ... я бы ожидал, что классы (конструкторы) видны снаружи.
Робс
@robsch Его пример не принимает никаких параметров, но большинство будет. Смотрите мой пример здесь, чтобы узнать, как это обычно делается (TypeScript, но на 99% то же самое): repl.it/@fatso83/Module-Pattern-in-TypeScript
oligofren
88

Я стараюсь избегать включения любого JavaScript в HTML. Весь код инкапсулирован в классы, и каждый класс находится в своем собственном файле. Для разработки у меня есть отдельные теги <script> для включения каждого файла js, но они объединяются в один большой пакет для производства, чтобы уменьшить накладные расходы на HTTP-запросы.

Как правило, у меня будет один «основной» js-файл для каждого приложения. Итак, если бы я писал «опросное» приложение, у меня был бы js-файл с именем «survey.js». Это будет содержать точку входа в код jQuery. Я создаю ссылки jQuery во время создания экземпляра, а затем передаю их в мои объекты в качестве параметров. Это означает, что классы javascript являются «чистыми» и не содержат ссылок на идентификаторы CSS или имена классов.

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

Я также считаю, что соглашение об именовании важно для удобства чтения. Например: я добавляю 'j' ко всем экземплярам jQuery.

В приведенном выше примере есть класс с именем DimScreen. (Предположим, что приглушается экран и появляется окно с предупреждением.) Ему нужен элемент div, который можно увеличить, чтобы покрыть экран, а затем добавить окно с предупреждением, поэтому я передаю объект jQuery. У jQuery есть концепция плагинов, но она казалась ограничивающей (например, экземпляры не являются постоянными и недоступными) без реального преимущества. Таким образом, класс DimScreen будет стандартным классом javascript, который просто использует 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>');
  //...
};

Я построил несколько довольно сложных приложений, используя этот подход.

Джейсон Мур
источник
15
Я считаю, что использование $префикса имени переменной является более распространенной практикой, но я могу ошибаться. Так что $s = $('...')вместо этого jS = $('...')я предпочитаю просто вопрос предпочтений. Интересно, хотя, так как венгерская нотация считается запахом кода. Странно, насколько некоторые из моих соглашений / предпочтений кода JavaScript отличаются от моих соглашений о кодировании C # / Java.
jamiebarrow
9
@jamie В данном случае это не запах кода, это один из немногих случаев, когда венгерский язык хорош . Вы можете прочитать это .
Дан Абрамов
3
@DanAbramov спасибо за ссылку. Я действительно должен прочитать все блоги Джоэла, он так хорошо все объясняет. Определенно заслуживает славы / репутации, которую он имеет. Теперь я буду называть Systems Hungarianэто запахом кода и Apps Hungarianпрактикой :)
jamiebarrow
Я полагаю, что в мире C # это может быть отличной статьей для продвижения использования var, теперь, когда я думаю об этом. Большинство аргументов против использования var- это когда вы не будете уверены в «типе» того, что возвращается, но я думаю, что аргумент должен быть против того, чтобы не знать «класс» того, что возвращается. Если вы используете Apps Hungarian, у вас не должно быть этой проблемы, тогда ... интересно.
jamiebarrow
3
@Marnen: я понимаю вашу точку зрения, но она не бесполезна в качестве руководства для программиста. Префикс $ напоминает мне, что это при чтении моего кода позже, и, таким образом, помогает быстрее понять.
Шон
39

Вы можете разбить свои сценарии на отдельные файлы для разработки, а затем создать «релизную» версию, в которой вы соберете их все вместе и запустите YUI Compressor или что-то подобное на нем.

Greg
источник
Иногда возникают ненужные сценарии JavaScript. Это расточительно, чтобы отправить их клиенту. Я думаю, что стоит только отправлять то, что нужно. Конечно, для веб-приложения, которое используется в течение всего дня, такого как приложение для интрасети, может быть лучше отправить весь пакет сразу, при загрузке первой страницы.
DOK
2
Компиляция @DOK должна включать удаление неиспользованного материала.
aehlke
Есть также концепция отложенной загрузки, чтобы попытаться уменьшить потребности в полосе пропускания, когда вы загружаете начальную страницу, а затем выполняете асинхронную загрузку необходимых файлов сценария (как упоминалось в других ответах на этот вопрос). Тем не менее, это может потребовать больше запросов и на самом деле может быть менее полезным. @ DOK, если JS кэшируется, один средний запрос может быть лучше, чем несколько маленьких.
jamiebarrow
27

Вдохновленный ранее посты , которые я сделал копию Rakefile и поставщика каталогов , распределенных с WysiHat (а RTE упомянутый журнал изменений) и сделал несколько изменений , чтобы включить код проверки с JSLint и Минимизация с YUI Compressor .

Идея состоит в том, чтобы использовать Sprockets (из WysiHat) для объединения нескольких сценариев JavaScripts в один файл, проверить синтаксис объединенного файла с помощью JSLint и минимизировать его с помощью YUI Compressor перед распространением.

Предпосылки

  • Java Runtime
  • рубин и грабли
  • Вы должны знать, как поместить JAR в Classpath

Сейчас делаю

  1. Загрузите Rhino и поместите JAR ("js.jar") в ваш путь к классам
  2. Загрузите YUI Compressor и поместите JAR (build / yuicompressor-xyz.jar) в ваш путь к классам
  3. Загрузите WysiHat и скопируйте каталог "vendor" в корень вашего JavaScript-проекта
  4. Загрузите JSLint для Rhino и поместите его в каталог vendor

Теперь создайте файл с именем «Rakefile» в корневом каталоге проекта JavaScript и добавьте в него следующее содержимое:

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

Если вы все сделали правильно, вы сможете использовать в консоли следующие команды:

  • rake merge - объединить разные файлы JavaScript в один
  • rake check- проверить синтаксис вашего кода (это задание по умолчанию , поэтому вы можете просто набрать rake)
  • rake minify - подготовить минимизированную версию вашего JS-кода

По слиянию источников

Используя Sprockets, препроцессор JavaScript, вы можете включать (или require) другие файлы JavaScript. Используйте следующий синтаксис для включения других сценариев из исходного файла (с именем «main.js», но вы можете изменить это в 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
})();

А потом...

Взгляните на Rakefile, поставляемый с WysiHat, чтобы настроить автоматическое модульное тестирование. Хороший материал :)

А теперь ответ

Это не очень хорошо отвечает на исходный вопрос. Я знаю и сожалею об этом, но я разместил это здесь, потому что я надеюсь, что кому-то еще будет полезно организовать их беспорядок.

Мой подход к проблеме состоит в том, чтобы сделать как можно больше объектно-ориентированного моделирования и разделить реализации на разные файлы. Тогда обработчики должны быть максимально короткими. Пример с Listсинглтоном тоже хорош.

И пространства имен ... ну, они могут быть имитированы более глубокой структурой объекта.

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

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

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

Я не большой поклонник имитаций, но это может быть полезно, если у вас есть много объектов, которые вы хотели бы вывести из глобальной области видимости.

Дамир Зекич
источник
18

Организация кода требует принятия соглашений и стандартов документации:
1. Код пространства имен для физического файла;

Exc = {};


2. Групповые занятия в этих пространствах имен javascript;
3. Установите прототипы или связанные функции или классы для представления объектов реального мира;

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


4. Установите соглашения для улучшения кода. Например, сгруппируйте все свои внутренние функции или методы в его атрибуте class типа объекта.

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


5. Составьте документацию о пространствах имен, классах, методах и переменных. При необходимости также обсудите часть кода (некоторые FI и Fors, как правило, реализуют важную логику кода).

/**
  * 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;
    ...
};


Это всего лишь несколько советов, но это очень помогло в организации кода. Помните, что вы должны иметь дисциплину, чтобы добиться успеха!

Нери младший
источник
13

Следование хорошим принципам проектирования ОО и шаблонам проектирования значительно облегчает поддержку и понимание вашего кода. Но одна из лучших вещей, которые я обнаружил в последнее время, это сигналы и слоты, также известные как публикация / подписка. Взгляните на http://markdotmeyer.blogspot.com/2008/09/jquery-publish-subscribe.html для простой реализации jQuery.

Идея хорошо используется на других языках для разработки GUI. Когда что-то существенное происходит где-то в вашем коде, вы публикуете глобальное синтетическое событие, на которое могут подписаться другие методы в других объектах. Это дает отличное разделение объектов.

Я думаю, что Dojo (и Prototype?) Имеют встроенную версию этой техники.

см. также Что такое сигналы и слоты?

оборота мяу
источник
Я сделал это в JQuery. JS имеет встроенную модель событий, поэтому вам не нужно много поддержки фреймворка.
Марнен Лайбоу-Козер
12

Мне удалось успешно применить шаблон модуля Javascript к приложению Ext JS на моей предыдущей работе. Он предоставил простой способ создания красиво инкапсулированного кода.

Алан
источник
11

У Dojo была модульная система с самого первого дня. На самом деле он считается краеугольным камнем Додзё, клея, который скрепляет все это:

Использование модулей Dojo позволяет достичь следующих целей:

  • Пространства имен для кода Dojo и пользовательского кода ( dojo.declare()) - не загрязняют глобальное пространство, сосуществуют с другими библиотеками и пользовательским кодом, не поддерживающим Dojo.
  • Загрузка модулей синхронно или асинхронно по имени ( dojo.require()).
  • Пользовательские сборки путем анализа зависимостей модуля для создания одного файла или группы взаимозависимых файлов (так называемых слоев), включающих только то, что нужно вашему веб-приложению. Пользовательские сборки также могут включать в себя модули Dojo и предоставленные заказчиком модули.
  • Прозрачный доступ на основе CDN к Dojo и коду пользователя. И AOL, и Google носят Dojo таким же образом, но некоторые клиенты делают это и для своих пользовательских веб-приложений.
Евгений Лазуткин
источник
9

Проверьте JavasciptMVC .

Вы можете :

  • разделите ваш код на уровни модели, вида и контроллера.

  • сжать весь код в один производственный файл

  • автоматически генерировать код

  • создавать и запускать юнит-тесты

  • и многое другое ...

Лучше всего то, что он использует jQuery, поэтому вы также можете воспользоваться другими плагинами jQuery.

andyuk
источник
Да, я использовал jmvc, и это довольно хорошо - документы могли бы быть лучше, хотя
meouw
9

Мой босс все еще говорит о временах, когда они писали модульный код (язык C), и жалуется на то, насколько дрянным является код в наши дни! Говорят, что программисты могут писать ассемблер в любой среде. Всегда есть стратегия преодоления организации кода. Основная проблема с парнями, которые рассматривают java-скрипт как игрушку и никогда не пытаются его изучить.

В моем случае я пишу js-файлы на основе темы пользовательского интерфейса или экрана приложения с надлежащим init_screen (). Используя правильное соглашение об именах идентификаторов, я удостоверяюсь, что на уровне корневых элементов нет конфликтов пространства имен. В ненавязчивом window.load () я связываю вещи на основе идентификатора верхнего уровня.

Я строго использую закрытия и шаблоны java-скриптов, чтобы скрыть все частные методы. После этого никогда не сталкивался с проблемой конфликтующих свойств / определений функций / определений переменных. Тем не менее, при работе с командой часто бывает трудно обеспечить одинаковую строгость.

questzen
источник
9

Я удивлен, что никто не упомянул фреймворки MVC. Я использовал Backbone.js для модульной и развязки своего кода, и это было неоценимо.

Существует довольно много подобных фреймворков, и большинство из них тоже довольно крошечные. Мое личное мнение таково: если вы собираетесь писать больше, чем просто пару строк jQuery для ярких элементов пользовательского интерфейса, или хотите использовать богатое Ajax-приложение, инфраструктура MVC сделает вашу жизнь намного проще.

Четан
источник
8

«Писать как сумасшедший и просто надеяться, что у него получится лучше?», Я видел такой проект, который был разработан и поддержан всего двумя разработчиками, огромное приложение с большим количеством кода JavaScript. Кроме того, для каждой возможной функции jquery были разные ярлыки. Я предложил, чтобы они организовали код как плагины, так как это эквивалент jquery класса, модуля, пространства имен ... и всей вселенной. Но все стало намного хуже, теперь они начали писать плагины, заменяя каждую комбинацию из 3 строк кода, используемых в проекте. Лично я думаю, что jQuery - это дьявол, и его не следует использовать в проектах с большим количеством javascript, потому что он поощряет вас быть ленивым и не думать об организации кода каким-либо образом. Я предпочел бы прочитать 100 строк JavaScript, чем одну строку с 40 связанными функциями jQuery (я я не шучу) Вопреки распространенному мнению, очень легко организовать код JavaScript в эквивалентах пространств имен и классов. Это то, что делают YUI и Dojo. Вы можете легко бросить свой собственный, если хотите. Я считаю, что подход YUI намного лучше и эффективнее. Но вам обычно нужен хороший редактор с поддержкой фрагментов, чтобы компенсировать соглашения об именах YUI, если вы хотите написать что-нибудь полезное.

Васил
источник
3
Я бы согласился с вами по поводу действительно длинных цепочечных команд, но одна из лучших частей jQuery - это то, что он держит весь Javascript вне HTML. Вы можете настроить обработчики событий для всех ваших элементов, не «добавляя» идентификаторы или события «что угодно» в ваших элементах. Как всегда, чрезмерное использование любого инструмента плохо ...
Hugoware
Я работал над огромными, хорошо организованными проектами в jQuery. Я не знаю, почему вы думаете, что это мешает организации.
Марнен Лайбоу-Козер
7

Я создаю синглтоны для каждой вещи, которую мне действительно не нужно создавать несколько раз на экране, классы для всего остального. И все они помещены в одно пространство имен в одном файле. Все комментируется и разрабатывается с помощью UML, диаграмм состояний. Код javascript не содержит html, поэтому нет встроенного javascript, и я склонен использовать jquery, чтобы минимизировать проблемы между браузерами.

Никола Стеля
источник
3
хорошее комментирование - КЛЮЧ - я рада, что вы это сказали, поэтому мне не пришлось. Я бы добавил согласованные соглашения об именах, какую-то легко понятную стратегию организации для переменных & amp; функции, и, как вы упомянули, разумное использование классов по сравнению с одиночными.
Мэтт Лохкамп
Нет. Если вам нужны комментарии, ваш код обычно недостаточно читабелен. Стремитесь писать код, который не нуждается в комментариях.
Марнен Лайбоу-Козер
Кроме того, если вам нужны UML и диаграммы состояний, это, вероятно, означает, что ваша архитектура недостаточно понятна из кода. Downvoting.
Марнен Лайбоу-Козер
1
@Marnen Хорошо написанные проекты включают комментарии для описания ПОЧЕМУ, а не обязательно ЧТО. Код уже описывает ЧТО, но часто вам нужно что-то, чтобы описать ПОЧЕМУ. Upvoting.
Cypher
@Cypher Хорошо написанные проекты имеют достаточно четкий код, который вы обычно можете сказать «почему», а не просто «что». Я бы не стал доверять комментарию, чтобы сказать мне «почему», потому что у меня нет гарантии, что он синхронизирован с кодом. Пусть код документа сам.
Марнен Лайбоу-Козер
6

В моем последнем проекте - Viajeros.com - я использовал комбинацию нескольких методов. Я не знаю, как организовать веб-приложение - Viajeros - это сайт социальной сети для путешественников с четко определенными разделами, поэтому код для каждой области легко разделить.

Я использую имитацию пространства имен и ленивую загрузку модулей в соответствии с разделом сайта. На каждой странице загрузки я объявляю объект "vjr" и всегда загружаю в него набор общих функций (vjr.base.js). Затем каждая HTML-страница решает, какие модули нужны, с помощью простого:

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

Vjr.base.js получает каждый gzip-файл с сервера и выполняет их.

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

Каждый «модуль» имеет такую ​​структуру:

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

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

Данита
источник
6

Организация вашего кода в JS-образе, ориентированная на NameSpace, может выглядеть следующим образом ... и не будет конфликтовать с другими API Javascript, такими как 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>

Надеюсь это поможет.

Дэррил
источник
Это кажется мне немного грузоподъемностью. jQuery.fnявляется указателем на jQuery.prototype, потому что $()фактически возвращает новый экземпляр функции конструктора jQuery. Добавление «плагина» в jQuery означает просто расширение его прототипа. Но то, что вы делаете, это не так, и есть более чистые способы сделать то же самое.
Адам Лассек
Я считаю, что он просто создает статические функции. Я помню, как видел в документах jQuery, что такой способ объявления статических функций приемлем
Alex Heyd
6

Хороший принцип OO + MVC определенно будет иметь большое значение для управления сложным приложением javascript.

По сути, я систематизирую свое приложение и javascript со следующим знакомым дизайном (который существует еще со времен моего рабочего стола до Web 2.0)

JS OO и MVC

Описание для числовых значений на изображении:

  1. Виджеты, представляющие взгляды моего приложения. Это должно быть расширяемым и аккуратно выделенным, что приведет к хорошему разделению, которого MVC пытается достичь, вместо того, чтобы превращать мой виджет в код спагетти (эквивалентно в веб-приложении для помещения большого блока Javascript непосредственно в HTML). Каждый виджет общается через других, слушая событие, сгенерированное другими виджетами, тем самым уменьшая сильную связь между виджетами, которая может привести к неуправляемому коду (помните день добавления onclick везде, указывающего на глобальные функции в теге сценария? Urgh ...)
  2. Объектные модели, представляющие данные, которые я хочу заполнить в виджетах и ​​передавать туда и обратно на сервер. Инкапсулируя данные в свою модель, приложение становится независимым от формата данных. Например: хотя, естественно, в Javascript эти объектные модели в основном сериализуются и десериализуются в JSON, если каким-то образом сервер использует XML для связи, все, что мне нужно изменить, - это изменить уровень сериализации / десериализации и необязательно менять все классы виджетов. ,
  3. Классы контроллеров, которые управляют бизнес-логикой и взаимодействием с сервером + иногда уровень кэширования. Этот уровень управляет протоколом связи с сервером и помещает необходимые данные в объектные модели.
  4. Классы аккуратно обернуты в соответствующие им пространства имен. Я уверен, что мы все знаем, насколько неприятным может быть глобальное пространство имен в Javascript.

В прошлом я разделял файлы на свои собственные js и использовал обычную практику для создания принципов ОО в Javascript. Проблема, которую я вскоре обнаружил, состоит в том, что есть несколько способов написания JS OO, и это не обязательно, что у всех членов команды одинаковый подход. По мере того, как команда становилась все больше (в моем случае более 15 человек), это усложняется, так как нет стандартного подхода к объектно-ориентированному Javascript. В то же время я не хочу писать свою собственную структуру и повторять некоторые работы, которые, я уверен, умнее людей, чем я решил.

jQuery невероятно хорош как Javascript Framework, и мне это нравится, однако, по мере того, как проект становится больше, мне явно нужна дополнительная структура для моего веб-приложения, особенно для упрощения стандартизации практики ОО. Для себя после нескольких экспериментов нахожу, что YUI3 Base и Widget ( http://yuilibrary.com/yui/docs/widget/ и http://yuilibrary.com/yui/docs/base/index.html ) обеспечивает именно то, что мне нужно. Несколько причин, почему я их использую.

  1. Он обеспечивает поддержку пространства имен. Реальная потребность в ОО и аккуратной организации вашего кода
  2. Это поддерживает понятие классов и объектов
  3. Это дает стандартизированные средства для добавления переменных экземпляра в ваш класс
  4. Он поддерживает расширение класса аккуратно
  5. Предоставляет конструктор и деструктор
  6. Обеспечивает рендеринг и привязку событий
  7. Имеет базовую структуру виджетов
  8. Каждый виджет теперь может общаться друг с другом, используя стандартную модель, основанную на событиях.
  9. Что наиболее важно, он дает всем инженерам стандарт OO для разработки Javascript

Вопреки многим представлениям, мне не обязательно выбирать между jQuery и YUI3. Эти двое могут мирно сосуществовать. Хотя YUI3 предоставляет необходимый шаблон OO для моего сложного веб-приложения, jQuery по-прежнему предоставляет моей команде простую в использовании абстракцию JS, которую мы все любим и знакомы.

Используя YUI3, мне удалось создать шаблон MVC, разделив классы, расширяющие базу как модель, классы, расширяющие виджет как представление, и, конечно, у вас есть классы контроллеров, которые выполняют необходимую логику и вызовы на стороне сервера.

Виджет может общаться друг с другом, используя модель, основанную на событиях, и прослушивая событие и выполняя необходимую задачу на основе предопределенного интерфейса. Проще говоря, размещение структуры OO + MVC в JS является для меня радостью.

Просто отказ от ответственности, я не работаю на Yahoo! и просто архитектор, который пытается справиться с той же проблемой, что и исходный вопрос. Я думаю, что если кто-нибудь найдет эквивалентную структуру OO, это также сработает В принципе, этот вопрос относится и к другим технологиям. Слава Богу за всех людей, которые придумали OO Principles + MVC, чтобы сделать наши дни программирования более управляемыми.

Момо
источник
5

Я использую управление пакетами ( dojo.requireи dojo.provide) Dojo и систему классов ( dojo.declareкоторая также допускает простое множественное наследование), чтобы модульно преобразовать все мои классы / виджеты в отдельные файлы. Это не только позволяет сохранить ваш код организованным, но и позволяет выполнять ленивую / своевременную загрузку классов / виджетов.

Джастин Джонсон
источник
3

Несколько дней назад ребята из 37Signals выпустили RTE-контроль с изюминкой. Они создали библиотеку, которая связывает файлы javascript с помощью команд препроцессора.

С тех пор я использую его для разделения моих файлов JS, а затем, в конце концов, объединяю их в один. Таким образом, я могу разделить проблемы и, в конце концов, иметь только один файл, который проходит через канал (gzipped, не меньше).

В своих шаблонах проверьте, находитесь ли вы в режиме разработки, и включите ли вы отдельные файлы, и, если вы работаете, включите последний (который вам придется «создавать» самостоятельно).

изменения
источник
1
getsprockets.org - прямая ссылка
Мэтт Гарднер
3

Создайте фальшивые классы и убедитесь, что все, что может быть добавлено в отдельную функцию, которая имеет смысл, сделано именно так. Также убедитесь, что вы много комментируете, и не пишите спагетти-код, а храните его в разделах. Например, какой-то бессмысленный код, изображающий мои идеалы. Очевидно, в реальной жизни я также пишу много библиотек, которые в основном охватывают их функциональность.

$(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.
    }
};
Дмитрий Фарков
источник
3

Используйте шаблоны наследования для организации больших приложений jQuery.

Четан
источник
Я начинаю использовать его, даже для очень маленьких / базовых вещей, и это действительно помогает сохранять код чистым и гибким. Это стоит использовать даже для простых JS-манипуляций на стороне клиента.
Четан
Это мне нравится и используется в моих приложениях.
Андреас
2

Я думаю, что это связано, возможно, с DDD (Domain-Driven Design). Приложение, над которым я работаю, хотя и не имеет формального API, намекает на это с помощью кода на стороне сервера (имена классов / файлов и т. Д.). Вооружившись этим, я создал объект верхнего уровня в качестве контейнера для всей проблемной области; Затем я добавил пространства имен, где это необходимо:

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');
кругозор
источник
2

Для организации JavaScript используется следующее

  1. Папка для всего вашего JavaScript
  2. Страница уровня javascript получает свой собственный файл с тем же именем страницы. ProductDetail.aspx будет ProductDetail.js
  3. Внутри папки javascript для библиотечных файлов у меня есть папка lib
  4. Поместите связанные библиотечные функции в папку lib, которую вы хотите использовать в своем приложении.
  5. Ajax - это единственный javascript, который я перемещаю за пределы папки javascript и получает свою собственную папку. Затем я добавляю две подпапки клиент и сервер
  6. Папка клиента получает все файлы .js, а папка сервера - все файлы на стороне сервера.
Джейсон Слишком Крутые Сети
источник
Хорошо для организации файлов. Я делаю это с помощью кода. Но в конце я компилирую свой код в ... скажем, dll. Это необходимо и для javascript, иначе вы будете запрашивать 15 js-файлов на страницу.
График
Нет ничего плохого в запросе 15 файлов JS на страницу. Ваш браузер будет кэшировать их для последующих запросов в любом случае.
Марнен Лайбоу-Козер
@ MarnenLaibow-Koser Единственная проблема, связанная с запросом 15 файлов JS на странице, заключается в том, сколько запросов HTTP может обрабатывать браузер за один раз. Таким образом, объединение их в один файл позволяет браузеру запрашивать другие необходимые файлы одновременно.
iwasrobbed
Это правда, но после первых двух попаданий они будут в кеше браузера, поэтому им не потребуются HTTP-соединения.
Марнен Лайбоу-Козер
2

Я использую эту маленькую вещь. Он дает вам директиву include для шаблонов JS и HTML. Это полностью устраняет беспорядок.

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
источник
2

Вы можете использовать jquery mx (используется в javascriptMVC), который представляет собой набор скриптов, который позволяет вам использовать модели, представления и контроллеры. Я использовал его в проекте и помог мне создать структурированный javascript с минимальными размерами сценариев из-за сжатия. Это пример контроллера:

$.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'));

Вы также можете использовать только сторону контроллера jquerymx, если вас не интересуют вид и части модели.

rolnn
источник
1

Твой вопрос мучил меня в конце прошлого года. Разница - передача кода новым разработчикам, которые никогда не слышали о частных и публичных методах. Мне пришлось построить что-то простое.

Конечным результатом была небольшая (около 1 КБ) инфраструктура, которая переводит объектные литералы в jQuery. Синтаксис визуально легче сканировать, и если ваш js становится действительно большим, вы можете написать повторно используемые запросы, чтобы найти такие вещи, как используемые селекторы, загруженные файлы, зависимые функции и т. Д.

Публиковать небольшие рамки здесь непрактично, поэтому я написал пост в блоге с примерами (Мое первое. Это было приключение!). Вы можете посмотреть.

Для любых других здесь с несколькими минутами, чтобы проверить это, я был бы очень признателен за обратную связь!

Рекомендуется FireFox, так как он поддерживает toSource () для примера запроса объекта.

Ура!

Адам

Адам
источник
0

Я использую собственный сценарий, вдохновленный поведением Бена Нолана (к сожалению, больше не могу найти текущую ссылку на это), чтобы хранить большинство моих обработчиков событий. Эти обработчики событий запускаются, например, элементами className или Id. Пример:

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

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

});

Мне нравится включать большинство моих библиотек Javascript на лету, кроме тех, которые содержат глобальное поведение. Для этого я использую помощник заполнителя headScript () Zend Framework , но вы также можете использовать javascript для загрузки других скриптов на лету, например, с помощью Ajile .

Арон Роттвил
источник
Это то, что ты искал? koders.com/javascript/...
ДОК
Да, это один! :) Похоже, что код ссылки более новый, чем версия, на которую я был вдохновлен. Спасибо за ваши усилия!
Арон Роттвил
0

Вы не упоминаете, какой у вас язык на стороне сервера. Или, более уместно, какую платформу вы используете - если таковая имеется - на стороне сервера.

IME, я организую вещи на стороне сервера и позволяю всему этому трястись на веб-странице. Фреймворку дана задача организовать не только JS, который должна загружать каждая страница, но и JS-фрагменты, которые работают с сгенерированной разметкой. Такие фрагменты, которые вы обычно не хотите, генерируются более одного раза - вот почему они абстрагируются в структуру для того, чтобы этот код заботился об этой проблеме. :-)

Для конечных страниц, которые должны испускать свой собственный JS, я обычно нахожу, что в сгенерированной разметке есть логическая структура. Такие локализованные JS часто могут быть собраны в начале и / или конце такой структуры.

Обратите внимание, что ничто из этого не освобождает вас от написания эффективного JavaScript! :-)

staticsan
источник
0

Ленивый Загрузить нужный код по требованию. Google делает что-то подобное со своим google.loader

Бриг Ламоро
источник