2013-10-01 70 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變量稍微快一些。 (這實際上是一個微型優化,但在這種情況下,它是方便由於不同的原因[爲清晰起見]。)