摘要:前綴命名空間如果命名空間的目的是避免沖突的話。語言程序經常使用前綴命名空間。我認為前綴命名空間是中最清楚明白的命名空間系統。對象命名空間的一個問題是它會導致與面向對象消息傳遞混淆。嵌套命名空間的幻覺在中也存在。
原文鏈接:《JavaScript Namespacing》
譯文原鏈:【譯】JavaScript 命名空間
JavaScript 中有很多可以給你的對象安全分配命名空間的方法。這篇文章討論我見過的普遍的實踐。
前綴命名空間如果命名空間的目的是避免沖突的話。下面這個系統,只要我們知道全局變量名前綴 myApp_ 是唯一的,可以像其他系統一樣避免命名空間沖突。
// add uniquely named global properties var myApp_sayHello = function() { alert("hello"); }; var myApp_sayGoodbye = function() { alert("goodbye"); }; // use the namespace properties myApp_sayHello();
C 語言程序經常使用前綴命名空間。在 JavaScript 的世界中,你可能會碰見 Macromedia 的 MM_ 方法,例如 MM_showHideLayers。
我認為前綴命名空間是 JavaScript 中最清楚明白的命名空間系統。(下面的對象命名空間策略在加入了 this 關鍵字后會導致困惑。)
前綴命名空間的確創建了很多全局對象。這對于前綴用來避免的命名空間沖突并不是什么問題。前綴命名空間的問題是,有些網頁瀏覽器(例如 IE6)在有很多全局對象時表現很糟糕,就我所聽說。我做了一些測試并且發現有一個 comp.lang.javascript 的小線程,不過我沒有就這個話題研究徹底。
單對象命名空間當下,最流行的 JavaScript 命名空間實踐是使用一個全局變量來引用一個對象。這個被引用的對象引用你的『真正的業務』,并且因為你的全局對象的命名獨一無二,你的代碼和其他人的代碼就可以一起嗨皮地運行。
如果你確定這個世界上沒有任何人用了這個全局變量名 myApp,那么你可以有這樣的代碼:
// define the namespace object var myApp = {}; // add properties to the namespace object myApp.sayHello = function() { alert("hello"); }; myApp.sayGoodbye = function() { alert("goodbye"); }; // use the namespace properties myApp.sayHello();
當上面代碼的最后一行執行時,JavaScript 解釋器首先找到 myApp 對象,然后找到并調用這個對象的 syaHello 屬性。
對象命名空間的一個問題是它會導致與面向對象消息傳遞混淆。這兩者之間并沒有明顯的句法差異:
// 1 namespace.prop(); // 2 receiver.message();
更仔細地研究這個混淆,我們得出下面的命名空間想法。假設我們有以下庫。
var myApp = {}; myApp.message = "hello"; myApp.sayHello = function() { alert(myApp.message); };
用這個庫的代碼可以隨意進行寫操作。
myApp.sayHello(); // works var importedfn = myApp.sayHello; importedfn(); // works
將這個和那個令人混淆的使用 this 的消息傳遞版本比較一下。
var myApp = {}; myApp.message = "hello"; myApp.sayHello = function() { alert(this.message); };
用這個庫的代碼可以隨意進行寫操作。
myApp.sayHello() // works because "this" refers to myApp object. var importedfn = myApp.sayHello; importedfn(); // error because "this" refers to global object.
這里面的要上的一課是,this 永遠不能引用一個被作為命名空間的對象因為它肯能導致關于從命名空間引入標識符的混淆。這個問題是 this 在我的 JavaScript Warning Words 列表中的原因之一。
(這也表明了庫的 API 屬性應該指向用一個方法,這樣這些方法可以被導入其他命名空間。這個問題是在我的文章 Lazy Function Definition Pattern 的評論中被指出的。懶惰方法定義可以在被隱藏在庫中并且不是 API 的部分時安全使用。)
嵌套對象命名空間嵌套對象命名空間是另一個普遍的實踐,它擴展了對象命名空間的想法。你可能見過類似如下代碼:
YAHOO.util.Event.addListener(/*...*/)
解決上面的代碼需要解釋器首先找到全聚德 YAHOO 對象,然后它的 util 對象,然后它的 Event 對象,然后找到并調用它的 addListener 屬性。這樣的話每次事件處理器綁定到一個 DOM 元素上花的功夫太多了,因此導入的概念開始被采用。
(function() { var yue = YAHOO.util.Event; yue.addListener(/*...*/); yue.addListener(/*...*/); })();
如果你清楚 YAHOO.util.Event.addListener 方法不會用 this 關鍵字并且永遠引用同一個方法,那么導入可以變得更加簡潔。
(function() { var yuea = YAHOO.util.Event.addEventListener; yuea(/*...*/); yuea(/*...*/); })();
我覺得當目的只是避免標識符沖突時,嵌套對象命名空間的復雜是不必要的。難道 Yahoo! 還覺得這些全局標識符 YAHOO_util_Event 和 YAHOO_util_Event_addEventListener 不夠獨特嗎?
我認為使用嵌套對象命名空間的動機是要看起來和 Java 包命名傳統一樣,這在 Java 中開銷不大。例如,在 Java 中你可能看到如下:
package mytools.text; class TextComponent { /* ... */ }
一個這個類的完全合格的引用應該是 mytools.text.TextComponent。
下面是 Niemeyer 和 Knudsen (寫)的 Learning Java 中包命名的描述:
包名是按層級構成的,使用點分隔的命名傳統。包名組成成分給編譯器和運行系統構成了獨一無二的定位文件的路徑。然而,它們并沒在包之間創建其他的關系。并沒有什么『subpackage』的說法,事實上,包命名空間是直接的,而非層級的。在包層級關系特定部分的包僅僅是因為習慣而有關聯。比如,如果我們穿件了另一個叫做 mytools.text.poetry 的包(假設是為了跟詩有關的一些文字類),這些類并不是 mytools.text 包的一部分;它們沒有包成員的訪問權限。
嵌套命名空間的幻覺在 Perl 中也存在。在 Perl 中,嵌套包名由雙冒號分隔開。你可以看到如下 Perl 代碼:
package Red::Blue; our $var = "foo";
一個完全合格的上述變量引用應該是 $Red::Blue::var。
在 Perl 中,就像 Java,命名空間層級的主意只是方便程序員,而不是語言本身要求。Wall,Christiansen 和 Orwant 的 Programming Perl 解釋道:
雙冒號可被用于鏈接在包名 $Red::Blue::var 中標識符。這意味著 $var 屬于包 Red::Blue。包 Red::Blue 跟可能存在的 Red 包或 Blue 包一點關系都沒有。只是說,Red::Blue 和 Red 或者 Blue 之間的關系可能對于寫代碼或者使用這個程序的人有什么意義,但跟 Perl 沒關系。(好吧,除了在現在的實現中,符號表 Red::Blue 剛好存在符號表 Red 中。但是 Perl 語言并沒有直接利用過它。)
上述引用中最后備注暗示了 Perl 可能有和在 JavaScript 中使用嵌套命名空間對象一樣的標識符沖突開銷。如果 Perl 的實現改變了,這個開銷就會消失。在 JavaScript 中,我肯定嵌套對象命名空間的開銷永遠不會消失因為 JavaScript 使用延遲綁定。
我并不認為 JavaScript 中的嵌套對象命名空間提供了任何大好處,不過如果不使用導入的話在運行時可能會開銷非常大。
一個折中方案如果單純地前綴命名空間在某些瀏覽器中真的很慢,而嵌套命名空間的概念幫助在開發者腦中保持各事務的有序,那我認為上述 Yahoo! 的例子也可以這樣寫:
YAHOO.util_Event_addListener
或者用更多的全局名稱:
YAHOO_util_Event.addListener哪個維度的命名空間?
Perl 的 CPAN 模塊是基于他們所做的事情進行命名空間管理的。例如,我寫了一個這個命名空間里的模塊:
JavaScript::Minifier
如果別人用同樣的名字寫他自己的模塊,并且他不自知地通過某些模塊依賴通過同一個名字使用 CPAN 模塊,那么就會有沖突。
Java 程序員采用最冗長但當然也是最安全的方法。(Java 程序員似乎都想著在大型系統上運行的代碼。)在 Java 中,包經常是基于誰寫的和做什么的來命名。(myFunc風格的規范化。)『誰寫的』部分甚至使用開發者自己的相對可以保證唯一性的名字。如果我寫一個 Java 的 minifier,因為我有 michaux.ca 的域名,我可能用以下命名空間:
ca.michaux.javascript.minifier
在 JavaScript 中,經過這次討論,可能這樣寫效率更高:
ca_michaux_javascript_minifier
因為 JavaScript 是以文本的形式服務的,這樣的命名空間可能開銷太大,因為增加了下載時間。Gzip 壓縮會找到公共的字符串并用短字符串替換它們。如果 gzip 不可用的話那么就可以考慮使用導入了。
var ca_michaux_javascript_minifier = {}; (function() { var cmjm = ca_michaux_javascript_minifier; // refer to cmjm inside this module pattern })();
我并不是說這些長的命名空間是絕對必須的,不過他們一定是避免命名空間沖突的最安全方法。
其他命名空間問題標識符不僅在 JavaScript 資源中創建。一個表單的 name 屬性也被加在 document.forms 對象上。像 這樣命名是有意義的。
命名空間類名屬性,比如
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。 轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79812.html
摘要:原文鏈接譯文原鏈譯中的命名空間全局變量應該由有系統范圍相關性的對象們保留,并且它們的命名應該避免含糊并盡量減少命名沖突的風險。其他的考慮我希望避免命名空間嵌套。因為并沒有正式的命名空間結構,所以有很多自然形成的方法。 原文鏈接: Namespacing in JavaScript譯文原鏈: 【譯】JavaScript 中的命名空間 全局變量應該由有系統范圍相關性的對象們保留,并且它們的...
摘要:原文鏈接原文作者你想知道的關于作用域的一切譯中有許多章節是關于的但是對于初學者來說甚至是一些有經驗的開發者這些有關作用域的章節既不直接也不容易理解這篇文章的目的就是為了幫助那些想更深一步學習了解作用域的開發者尤其是當他們聽到一些關于作用域的 原文鏈接: Everything you wanted to know about JavaScript scope原文作者: Todd Mott...
摘要:比如,我們可以監聽事件由實例發出,然后在任何瀏覽器中就是變化的時候都會得到通知,如下所示每一個作用域對象都會有這個方法,可以用來注冊一個作用域事件的偵聽器。這個函數所扮演的偵聽器在被調用時會有一個對象作為第一個參數。 上一篇:【譯】《精通使用AngularJS開發Web App》(二) 下一篇:【譯】《精通使用AngularJS開發Web App》(四) 書名:Mastering W...
摘要:通用格式規范縮進一次縮進個空格,不要使用或者混合和空格的縮進。語義化根據使用場景選擇正確的元素有時被錯誤的稱為標簽。格式規范引號屬性值用雙引號。風格規范和命名使用有含義的和名稱。和單位值為時不用添加單位。 原文 Google HTML/CSS Style Guide 背景 這篇文章定義了 HTML 和 CSS 的格式和代碼規范,旨在提高代碼質量和協作效率。 通用樣式規范 協議 圖片,樣...
摘要:通用格式規范縮進一次縮進個空格,不要使用或者混合和空格的縮進。語義化根據使用場景選擇正確的元素有時被錯誤的稱為標簽。格式規范引號屬性值用雙引號。風格規范和命名使用有含義的和名稱。和單位值為時不用添加單位。 原文 Google HTML/CSS Style Guide 背景 這篇文章定義了 HTML 和 CSS 的格式和代碼規范,旨在提高代碼質量和協作效率。 通用樣式規范 協議 圖片,樣...
閱讀 1260·2021-11-23 09:51
閱讀 1627·2021-11-16 11:45
閱讀 4013·2021-10-09 09:43
閱讀 2681·2021-07-22 16:47
閱讀 944·2019-08-27 10:55
閱讀 3449·2019-08-26 17:40
閱讀 3083·2019-08-26 11:39
閱讀 3228·2019-08-23 18:39