2013-10-01 2 views
3

У меня возникли проблемы дешифровки следующий Javascript инициализации заявление:Расширенный Javascript инициализации

(function(NAMESPACE) { 
     NAMESPACE.nav = {}; 
     var nav = NAMESPACE.nav, 

_init = false, 
     _isNavOpen = false, 
     _inner = document.getElementById('inner-wrap'); 

    // constants 
    nav.CLASS = 'js-nav-open'; 
    nav.CLASS_READY = 'js-nav'; 
    nav.CONTAINER = '#nav'; 
    nav.DURATION = 400; 
    nav.HAS_CSSTRANSITIONS = $('html').hasClass('csstransitions') && $('html').hasClass('csstransforms3d'); 

... ...

// toggle open/close 
    nav.toggle = function(event) { 
     event.stopPropagation(); 

     if(_isNavOpen && $('html').hasClass(nav.CLASS)) { 
      nav.close(); 
     } else { 
      nav.open(); 
     } 

     // this is for the links 
     if(event) { 
      event.preventDefault(); 
     } 
    }; 

}(PROJECT_NAME)); 

кажется излишне сложным - вызов (или установка?) «nav» 3 раза в 2 строках. Может кто-нибудь, пожалуйста, объясните, в чем дело?

+1

Это как расширяющийся, так и внешний объект (переданный) и создающий локальную переменную. – bfavaretto

+1

Вместо этого вы можете сделать «var nav = NAMESPACE.nav = {};». Или даже опустить локальные переменные, но это похоже на удобное обращение к пространству имен позже в коде. –

+0

@bfavaretto спасибо за комментарий - я вижу, что вы имеете в виду (прошел). – timmackay

ответ

3

Вот строка за строкой объяснение (с заголовками просто разбить его):

Настройка:

// Create an anonymous function expression taking `NAMESPACE` as a parameter. 
// Likely the *real* namespace will be passed to the function at the end 
// with ... })(realnamespacetomodify); 
(function(NAMESPACE) { 

// Create the new part of the namespace. Note that we are editing a reference 
// so really this change happens on whatever object was passed in. 
    NAMESPACE.nav = {}; 

// Create a local pointing to this new sub-namespace. Probably just for 
// convenience, also possibly for portability (if the name is used in closures, 
// then those closures don't need to refer to NAMESPACE directly). 
    var nav = NAMESPACE.nav, 

определение модуля:

// While nav refers to an object likely in global scope, nav itself can 
// never be referred to from global scope because it is a local here. 

// These variables are local here. They can never be referred to by global scope. 
    _isNavOpen = false, 
    _inner = document.getElementById('inner-wrap'); 

// These variables, added to nav, can be accessed using the object that 
// nav refers to in global scope (see the end). 
    nav.CLASS = 'js-nav-open'; 
    ... 

// This function is also added to nav, therefore it can be accessed outside 
    nav.toggle = function(event) { 
     ... 

     // This reference to _isNavOpen resolves because this function 
     // is a closure, and binds variables outside its scope 
     // to the function itself. So even though _isNavOpen can't be 
     // accessed globally, it can be accessed here, making it like 
     // a private member of this namespace. 
     if(_isNavOpen && $('html').hasClass(nav.CLASS)) { 
      // nav is also bound by the closure and can be accessed here 
      nav.close(); 
     } ... 
    }; 

Использование в глобальном пространстве:

}(PROJECT_NAME)); 

console.log(PROJECT_NAME.nav.CLASS); // "js-nav-open" 
console.log(PROJECT_NAME.nav.toggle); // Function object 

Это шаблон модуля. Он используется по нескольким причинам:

  • переносимость кода (не относится к глобальным объектам внутри модуля)
  • Обзорного (избегая назначения ненужного ВАРА в глобальное пространство имен)
  • Видимости (скрытие переменные частного доступа)

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

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

(function() { 
    ... // Anything set here is local, not global. 

})(); 
+0

Спасибо за подробное разбиение @NickC. Это именно то, к чему я искал помощь. Я обновил код, чтобы включить несколько функций, а затем конец. – timmackay

+0

@hyperdouche Отлично! Добавлено еще несколько объяснений для остальной части. – Nicole

+0

Спасибо - объяснение того, что делает каждая вещь, именно то, с чем я искал помощь. Спасибо, что нашли время. – timmackay

4

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

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

+0

Итак, все функции, созданные в пределах области действия, доступны с помощью функции «NAMESPACE.myFunction»? – timmackay

+0

Да, это правильно, если они назначены этому пространству имен. Как правило, большинство плагинов JQuery настроены. Вы переходите в '$' и присоединяете к нему плагин, чтобы его можно было вызывать извне. – TGH

4

Это является обычной практикой при использовании JQuery:

(function ($) { 
    var div = $('#my-div'); 
    // Etc 
}(jQuery)); 

Обертывания скрипта в затворе обеспечивает, что некоторые переменные будут иметь значения, которые вы ожидаете от них.

Например, jQuery использует $ для выполнения почти всего. Большинство людей любят использовать $('do something'), а не jQuery('do something').

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

Обернув свой код в закрытии, вы «зарезервируете» $ как jQuery и только jQuery. (Когда вы передаете в jQuery в качестве аргумента закрытия, $ может только означает «Jquery», в рамках этой функции.)


Кроме того, в вашем примере, вы резервируете переменную NAMESPACE. Даже если бы существовала другая переменная, называемая NAMESPACE, вызывающая ракетку где-то еще на странице, передавая переменную в конце вашего закрытия, вам гарантируется, что NAMESPACE будет объектом, который вы ожидаете от нее (по крайней мере, в пределах закрытие).

Скажите, что у вас была глобальная переменная с именем AbominableSnowman, но вы хотели использовать AS в качестве ярлыка. При этом:

var AS = "Apple Soup"; 

(function (AS) { 
    AS.tellMeAboutSnowmen(); 
    alert(AS.snowballs); 
}(AbominableSnowman)); 

Ваш код по-прежнему будет функционировать так, как вы планировали. (Доказательство http://jsfiddle.net/RUzZH/1/)


Что касается «листать его вокруг,» кажется, что оригинальный программист хотел сократить NAMESPACE.nav вплоть до nav. Вероятно, это был лучший способ сделать это.

Альтернативой (не рекомендуется):

// It's best to limit your assignments to 1-per-line 
// This kind of code isn't fun to debug, or even read 
var nav = NAMESPACE.nav = {}; 

Это не похоже, что-то стоит разъедающий над. Однако, поскольку этот скрипт взаимодействует с NAMESPACE.nav довольно часто, он будет немного, немного быстрее, чтобы напрямую ссылаться на свойство .nav с переменной nav. (Это действительно микро-оптимизация, но в этом случае удобно оправдано по другой причине [ради ясности].)

Смежные вопросы