Зачем определять анонимную функцию и передавать ей jQuery в качестве аргумента?

99

Я просматриваю отличный демонстрационный код peepcode из скринкастов backbone.js. В нем основной код заключен в анонимную функцию, которая передается объекту jQuery:

(function($) {
  // Backbone code in here
})(jQuery);

В моем собственном базовом коде я только что заключил весь свой код в событие готовности jQuery DOM:

$(function(){
  // Backbone code in here
});

В чем смысл / преимущество первого подхода? Таким образом создается анонимная функция, которая затем немедленно выполняется с объектом jQuery, передаваемым в качестве аргумента функции, эффективно гарантируя, что $ является объектом jQuery. Это единственный момент - гарантировать, что jQuery привязан к «$», или есть другие причины для этого?

Мэтт Робертс
источник
4
Вместо этого вы должны были сначала просмотреть SO.
Александр
Взаимодействие с другими библиотеками - если автору страницы нужно использовать $.noConflict(), первый пример все равно будет работать.
DCoder
Возможный дубликат: jQuery и $ questions
Александр
Смотрите возможные дубликаты jQuery document.ready и самовызывающую анонимную функцию для разницы
Берги
@Alexander, но тогда другие люди сначала найдут этот вопрос на SO. :-)
caiosm1005

Ответы:

183

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

Модули JavaScript


(function($) {
  // Backbone code in here
})(jQuery);

Это шаблон «Модуль JavaScript», реализованный с помощью немедленно вызываемой функции.

Цель этого кода - обеспечить «модульность», конфиденциальность и инкапсуляцию вашего кода.

Реализация этого - функция, которая немедленно вызывается вызывающей (jQuery)круглой скобкой. Целью передачи jQuery в круглые скобки является обеспечение локальной области видимости глобальной переменной. Это помогает сократить накладные расходы на поиск $переменной и в некоторых случаях позволяет улучшить сжатие / оптимизацию для минификаторов.

Немедленно вызываемые функции выполняются, ну и сразу. Как только определение функции завершено, функция выполняется.

Функция jQuery "DOMReady"

Это псевдоним функции JQuery "DOMReady": http://api.jquery.com/ready/


$(function(){
  // Backbone code in here
});

Функция "DOMReady" в jQuery выполняется, когда DOM готова к манипулированию вашим кодом JavaScript.

Модули против DOMReady в магистральном коде

Определять код Backbone внутри функции JQuery DOMReady - плохой тон, и это может отрицательно сказаться на производительности вашего приложения. Эта функция не вызывается до тех пор, пока DOM не загрузится и не будет готов к работе. Это означает, что вы ждете, пока браузер хотя бы раз проанализирует DOM, прежде чем определять свои объекты.

Лучше определять объекты Backbone вне функции DOMReady. Я, среди многих других, предпочитаю делать это внутри шаблона модуля JavaScript, чтобы я мог обеспечить инкапсуляцию и конфиденциальность своего кода. Я обычно использую шаблон «Выявление модуля» (см. Первую ссылку выше) для обеспечения доступа к битам, которые мне нужны вне моего модуля.

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

Скорее всего, вы все равно будете использовать функцию DOMReady, даже если вы определите свои объекты Backbone где-то еще. Причина в том, что многим приложениям Backbone необходимо каким-то образом манипулировать DOM. Для этого вам нужно дождаться готовности DOM, поэтому вам нужно использовать функцию DOMReady для запуска вашего приложения после того, как оно было определено.

Вы можете найти множество примеров этого в Интернете, но вот очень простая реализация с использованием как модуля, так и функции DOMReady:



// Define "MyApp" as a revealing module

MyApp = (function(Backbone, $){

  var View = Backbone.View.extend({
    // do stuff here  
  });

  return {
    init: function(){
      var view = new View();
      $("#some-div").html(view.render().el);
    }
  };

})(Backbone, jQuery);



// Run "MyApp" in DOMReady

$(function(){
  MyApp.init();
});
Дерик Бейли
источник
1
Спасибо за подробный ответ. Я знал, что функция DOMReady вызывается только при срабатывании события готовности DOM, но никогда не думал, что это будет проблемой. Разделение кода на определение битов магистрали внутри модуля, а затем взаимодействие с ними в готовом домене действительно кажется лучшим подходом
Мэтт Робертс
2
Интересно, что в примере приложения "todo" с backbone src все в dom готово.
Мэтт Робертс
2
Не забывайте, что шаблон модуля javascript также называется файлом IIFE.
Jess
1
анонимные функции, по сути, выполняются одновременно с DOM, так как это сделать их более эффективными?
bhavya_w 09
14

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

Joidegn
источник
9

Это гарантирует, что вы всегда можете использовать $эту крышку, даже если $.noConflict()она использовалась.

Без этого закрытия вы должны были бы использовать jQueryвместо $всего времени.

ThiefMaster
источник
4

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

См. Http://docs.jquery.com/Plugins/Authoring#Getting_Started для получения дополнительной информации.

Эндрю Брок
источник
2

Используйте оба.

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

И метод ярлыка .ready (), необходимый для запуска javascript только после загрузки DOM:

(function($) {
    $(function(){
          //add code here that needs to wait for page to be loaded
    });

    //and rest of code here
})(jQuery);
Андрей
источник
Более короткая версия, которую я нашел в другом месте на SO (также защищает undefined) :jQuery(function ($, undefined) { /* Code */ });
Джаред Готте