Java-esque OOP в JavaScript и сбой jQuery

Я работаю над проектом, и я действительно пытаюсь написать объектно-ориентированный код JavaScript. Я только что начал читать Douglas Crockford JavaScript: "Хорошие детали" , и я быстро начинаю понимать, что запись OOP на Java-esque в JavaScript будет трудная задача.

До сих пор я написал что-то вроде следующего...

// index.html
$(document).ready(function() {

   $().SetUpElements();
});

// this is in a different js file
$.fn.SetUpElements = function() {

    // do stuff here
    $().UpdateElement();
};

// this is in yet another different js file
$.fn.UpdateElement = function() {

   // do stuff here
   var element = new Element(id, name); // continue doing work
};

function Element(id, name) {

   var id = id;
   var name = name;

   // other stuff
};

... идея состоит в том, что я хочу, чтобы объекты/функции были реорганизованы и развязаны как можно больше; Я хочу повторно использовать как можно больше кода. Я распространял много кода в разных файлах .js с целью группировки определенного соответствующего кода, так же, как если бы вы пишете разные классы в Java.

Поскольку я больше узнал о jQuery, я понял, что нотация $.fn.foo = function() { ... }; фактически добавляет эту функцию foo к прототипу всех объектов jQuery. Это что-то я должен делать? Я как-то неправильно использую jQuery?

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

** Примечание. Я не разрабатываю плагин jQuery. Я разрабатываю веб-приложение и сильно использую jQuery.

Ответ 1

Я бы сказал, что первый способ создания методов - это неправильное использование jQuery. Синтаксис jQuery.fn.foo обычно зарезервирован для функций, которые действуют на элемент DOM, но вы используете их как статические функции, используя пустой объект jQuery.

Если вы хотите создать статические функции в пространстве имен jQuery, вы можете сделать:

jQuery.foo = function(){};

затем вызовите его через:

jQuery.foo();

вместо:

jQuery.fn.foo = function(){};

который позволяет:

jQuery('#someElementId').foo();

В терминах ООП. существует много разных подходов (образец модуля, прототип, factory...). Как я обычно подхожу к нему, создается класс как статическая функция, а затем ссылается на него с ключевым словом new

(function($){
    var undefined;

    $.ClassName = function(options){
        var self = this;
        var cfg = $.extend(true, {}, this.defaults, options);

        // ********************
        // start:private
        // ********************
        function _init(){

        };

        // ********************
        // start:public
        // ********************
        this.methodName = function(){

        };

        _init();
    };

    $.ClassName.prototype.defaults = {};
})(jQuery);

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

Ответ 2

Если это не плагин jquery, я бы написал что-то вроде этого:

    var app = {
      init: function(){
        app.SetUpElements();
      },
      SetUpElements: function() {
        return 'something';
      }, 
      etc: function() {

      }
    };
   $(document).ready(app.init);

Ответ 4

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

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

Другим методом, который я видел, является предоставление одной функции init для вашего подключаемого модуля в пространстве имен jQuery, а затем создание дополнительного имени подключаемого модуля, доступного в глобальном пространстве имен, которое обеспечивает более прямой доступ к функции/члены и т.д. плагин Galleria - отличный пример того, как это сделать. Изучите их документацию и способ настройки структуры подключаемого модуля.

ИЗМЕНИТЬ

Увидев, что вы не создаете подключаемый модуль: многие из вещей, которые, как я сказал, по-прежнему применяются к общей разработке jQuery (и, действительно, к разработке в целом).

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

Что касается пространства имен, посмотрите на принятый ответ на этот вопрос для примера того, как это сделать правильно: Как объявить пространство имен в JavaScript?

И вот отличный ресурс для OO в JavaScript. Я использовал эту статью, пытаясь обернуть голову вокруг концепции: http://mckoss.com/jscript/object.htm

Ответ 5

Похоже, вы пишете весь свой код как плагины jQuery? Я бы этого не сделал. Создайте собственное пространство имен.

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

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

Ответ 6

Как уже упоминалось, если вы явно не создаете публичный плагин, не используйте пользовательские функции jQuery. Вместо этого создайте собственное пространство имен, используя простое обозначение объекта, или нечто более надежное, например Module Pattern. Если вы хотите сходить с ума, вы можете использовать API поверх API, чтобы получить более классический шаблон OO, используя Dean Edward Base. Конечной целью является извлечение ваших функциональных и дизайнерских требований из API jQuery. Таким образом, если вам когда-либо понадобится передать что-то в Mootools или Prototype, было бы намного проще выполнить.