Создание плагина jQuery: лучшие практики в отношении видимости функций?

Я создаю плагин jQuery. Пока он работает нормально, но у меня есть сомнения относительно того, как я делаю вещи:

jQuery.fn.myMethod = function() {
  return this.each(function(){
    MyScope.doSomething(jQuery(this).attr("id"));
  });
};

var MyScope = {

  // The functions contained in MyScope are extremely linked to the logic 
  // of this plugin and it wouldn't make a lot of sense to extract them

  doSomething: function(id){
    // something
    doSomethingElse(23);
    // some more code
    doSomethingElse(55);
  },

  doSomethingElse: function(someInt){
    // some code 
  }
};

Я использую MyScope для хранения всех моих функций "private". Я не хочу, чтобы пользователь мог идти $("p").doSomething(), но мне нужно их использовать.

Я мог бы перемещать все в функции myMethod, но это создавало бы 100-строчную функцию, и люди меня ненавидят.

Какие лучшие практики в этой ситуации? Есть ли отличные учебники по этому поводу?

Ответ 1

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

jQuery.fn.myMethod = function() {
  return this.each(function(){
    doSomething(jQuery(this).attr("id"));
  });        
  function doSomething(id){
    //do something
  }
  function doSomethingElse(){
    // some code
  }
};

Здесь вы можете просмотреть быстрое демо

"Я мог бы перемещать все в функции myMethod, но он создавал бы функцию длиной в 100 строк, и люди меня ненавидят"..... почему?

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

Есть несколько стилей для объявления, некоторые с тем же эффектом, параметр, который я дал, является одним из многих, но размещение вещей внутри myMethod является вполне разумным подходом.


Чтобы быть более полным, здесь другая альтернатива:

(function($) { 
    function doSomething(id){
      //do something, e.g:  doSomethingElse('bob');
    }
    function doSomethingElse(str){
      //some code
    }
    $.fn.myMethod = function() {
      return this.each(function(){
        doSomething(jQuery(this).attr("id"));
      });   
    };
})(jQuery);

Или другое:

(function($) { 
    var me = {
        doSomething: function(id){
         //do something, e.g:  this.doSomethingElse('bob');
        },
        doSomethingElse: function(str){
          //some code
        }
    };
    $.fn.myMethod = function() {
      return this.each(function(){
        me.doSomething(jQuery(this).attr("id"));
      });   
    };
})(jQuery);

Статьи по теме:

Ответ 2

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

(function() {
  function doSomething(id) {
    // Something
  }

  function doSomethingElse() {
    // Something else
  }

  jQuery.fn.myMethod = function() {
    return this.each(function(){
      doSomething(this.id);
    });
  };
})();

Ответ 3

Я бы поставил все внутри функции jQuery.fn.myMethod, чтобы избежать возможных конфликтов пространства имен и сделать для более чистого кода. Этот шаблон также позволяет вам создавать частные методы, которые недоступны из-за пределов функции myMethod.

jQuery.fn.myMethod = function(options) {
  // Set up a "that" object, which can be referenced from anywhere inside this function
  var that = {};

  // If the plugin needs optional arguments, you can define them this way
  if (typeof(options) == 'undefined') options = {};
  that.options.option1 = options.option1 || 'default value 1';
  that.options.option2 = options.option2 || 'default value 2';

  that.init = function() {
    // psuedo-constructor method, called from end of function definition
  }

  that.doSomething = function() {
    // something
  }

  that.doSomethingElse = function() {
    // something else
  } 

  // Call init method once all methods are defined
  that.init();

  // Return the matched elements, to allow method chaining
  return jQuery(this);
}