摘要:示例如下可以很容易的為對象字面量定義功能可以進一步支撐對象命名空間與為對象添加屬性一樣,我們也可以直接將屬性添加到命名空間。對象字面量方法不會污染全局命名空間,并在邏輯上協助組織代碼和參數。
簡介
在SF上看到這樣一個提問:
如題,因為不得已的原因,需要寫若干個全局函數。但又不想這樣:
window.a = function(){} window.b = function(){} window.c = function(){}
題主問有什么好的寫法?
解答:
如果你用 jQuery,你可以這樣寫
$.extend(window, { a: function() {}, b: function() {}, c: function() {} });
如果你不用 jQuery,可以直接實現類似的 extend:
(() => { var defining = { a: function() { }, b: function() { }, c: function() { } }; Object.keys(defining).forEach(key => { window[key] = defining[key]; }); })();
在JavaScript中,命名空間可以幫助我們防止與全局命名空間下的其他對象或變量產生沖突。命名空間也有助于組織代碼,有更強的可維護性和可讀性。本文旨在探討JavaScript里的幾種常見命名空間模式,為我們提供一個思路。
一般命名空間的實現都以window為根。當向window申請a.b.c的命名空間時,首先在window中查看是否存在a這個成員,如果沒有則在 window下新建一個名為a的空關聯數組,如果已經存在a,則繼續在window.a中查看b是否存在,以此類推。下面分別是Atlas和YUI中的實現方法。
Atlas命名空間的實現方法:
Function.registerNamespace =function(namespacePath){ //以window為根 var rootObject =window; //對命名空間路徑拆分成數組 var namespaceParts =namespacePath.split("."); for (var i =0;iYUI命名空間的實現方法:
var YAHOO = window.YAHOO || {}; YAHOO.namespace = function(ns) { if (!ns || !ns.length) { return null; } var levels = ns.split("."); var nsobj = YAHOO; //如果申請的命名空間是在YAHOO下的,則必須忽略它,否則就成了YAHOO.YAHOO了 for (var i=(levels[0] == "YAHOO") ? 1 : 0; iYUI把所有申請的命名空間都放在了window.YAHOO下面,這樣有什么好處呢?假如Yahoo和其他公司有合作關系, 需要嵌入對方的腳本時,這樣能保證它自己編寫的代碼都在YAHOO這個空間下面,而其他公司不大可能在這個空間下面編碼,就基本不會出現命名沖突的情況。
我們一般的實現方式:
namespace = function(){ var argus = arguments; for(var i = 0; i < argus.length; i++){ var objs = argus[i].split("."); var obj = window; for(var j = 0; j < objs.length; j++){ obj[objs[j]] = obj[objs[j]] || {}; obj = obj[objs[j]]; } } return obj; }; namespace("tools.base");當然我們也常常利用js對象字面量的方式來實現js的命名空間:
var school = { addClass:function(classnum){ console.log(classnum); }, addStudent:function(stuId){ console.log(stuId); } } school.addClass("2");在全局作用域中聲明的任何變量和函數都是window對象的屬性,當名稱有沖突時,就會產生一些不可控的問題。全局變量會帶來以下問題:
命名沖突
代碼的脆弱性
難以測試
在編程開發中合理的使用命名空間,可以避免相同的變量或對象名稱產生的沖突。而且,命名空間也有助于組織代碼,有更強的可維護性和可讀性。JavaScript中雖然沒有提供原生的命名空間支持,但我們可以使用其他的方法(對象和閉包)實現類似的效果。下面就是一些常見的命名空間模式:
1.單一全局變量JavaScript中一個流行的命名空間模式是選擇一個全局變量作為主要的引用對象。因為每個可能的全局變量都成為唯一全局變量的屬性,也就不用再創建多個全局變量,那么也就避免了和其他聲明的沖突。
單一全局變量模式已經在不少的JavaScript類庫中使用,如:
YUI定義了唯一的YUI全局對象
jQuery定義了$和jQuery,$由其他類庫使用時使用jQuery
Dojo定義了一個Dojo全局變量
Closure類庫定義了一個goog全局對象
Underscore類庫定義了一個_ 全局對象
示例如下:
var myApplication = (function() { var count = 1; function funcur() { console.log(count); }; return { funcur:funcur } })(); myApplication.funcur();雖然單一全局變量模式適合某些情況,但其最大的挑戰是確保單一全局變量在頁面中是唯一使用的,不會發生命名沖突
2.命名空間前綴命名空間前綴模式其思路非常清晰,就是選擇一個獨特的命名空間,然后在其后面聲明聲明變量、方法和對象。示例如下:
var myApplication_propertyA = {}; var myApplication_propertyB = {}; function myApplication_myMethod() { // *** }從某種程度上來說,它確實減少了命名沖突的發生概率,但其并沒有減少全局變量的數目。當應用程序規模擴大時,就會產生很多的全局變量。在全局命名空間內,這種模式對其他人都沒有使用的這個前綴有很強的依賴,而且有些時候也不好判斷是否有人已經使用某個特殊前綴,在使用這種模式時一定要特別注意。
3.對象字面量表示法對象字面量模式可以認為是包含一組鍵值對的對象,每一對鍵和值由冒號分隔,鍵也可以是代碼新的命名空間。示例如下:
var myApplication = { // 可以很容易的為對象字面量定義功能 getInfo:function() { // *** }, // 可以進一步支撐對象命名空間 models:{}, views:{ pages:{} }, collections:{} };與為對象添加屬性一樣,我們也可以直接將屬性添加到命名空間。對象字面量方法不會污染全局命名空間,并在邏輯上協助組織代碼和參數。并且,這種方式可讀性和可維護性非常強,當然我們在使用時應當進行同名變量的存在性測試,以此來避免沖突。下面是一些常用的檢測方法:
var myApplication = myApplication || {}; if(!myApplication) { myApplication = {}; } window.myApplication || (window.myApplication || {}); // 針對jQuery var myApplication = $.fn.myApplication = function() {}; var myApplication = myApplication === undefined ? {} :myApplication;對象字面量為我們提供了優雅的鍵/值語法,我們可以非常便捷的組織代碼,封裝不同的邏輯或功能,而且可讀性、可維護性、可擴展性極強。
4.嵌套命名空間嵌套命名空間模式可以說是對象字面量模式的升級版,它也是一種有效的避免沖突模式,因為即使一個命名空間存在,它也不太可能擁有同樣的嵌套子對象。示例如下:
var myApplication = myApplication || {}; // 定義嵌套子對象 myApplication.routers = myApplication.routers || {}; myApplication.routers.test = myApplication.routers.test || {};當然,我們也可以選擇聲明新的嵌套命名空間或屬性作為索引屬性,如:
myApplication["routers"] = myApplication["routers"] || {};使用嵌套命名空間模式,可以使代碼易讀且有組織性,而且相對安全,不易產生沖突。其弱點是,如果我們的命名空間嵌套過多,會增加瀏覽器的查詢工作量,我們可以把要多次訪問的子對象進行局部緩存,以此來減少查詢時間。
5.立即調用的函數表達式立即調用函數(IIFE)實際上就是匿名函數,被定義后立即被調用。在JavaScript中,由于變量和函數都是在這樣一個只能在內部進行訪問的上下文中被顯式地定義,函數調用提供了一種實現私有變量和方法的便捷方式。IIFE是用于封裝應用程序邏輯的常用方法,以保護它免受全局名稱空間的影響,其在命名空間方面也可以發揮其特殊的作用。示例如下:
;(function (namespace, undefined) { // 私有屬性 var foo = "foo"; bar = "bar"; // 公有方法和屬性 namespace.foobar = "foobar"; namespace.sayHello = function () { say("Hello World!"); }; // 私有方法 function say(str) { console.log("You said:" + str); }; })(window.namespace = window.namespace || {}); console.log(namespace.foobar); //foobar可擴展性是任何可伸縮命名空間模式的關鍵,使用IIFE可以輕松實現這一目的,我們可以再次使用IIFE給命名空間添加更多的功能。
6.命名空間注入命名空間注入是IIFE的另一個變體,從函數包裝器內部為一個特定的命名空間“注入”方法和屬性,使用this作為命名空間代理。這種模式的優點是可以將功能行為應用到多個對象或命名空間。示例如下:
var myApplication = myApplication || {}; myApplication.utils = {}; ;(function () { var value = 5; this.getValue = function () { return value; } // 定義新的子命名空間 this.tools = {}; }).apply(myApplication.utils); (function () { this.diagnose = function () { return "diagnose"; } }).apply(myApplication.utils.tools); // 同樣的方式在普通的IIFE上擴展功能,僅僅將上下文作為參數傳遞并修改,而不是僅僅使用this還有一種使用API來實現上下文和參數自然分離的方法,該模式感覺更像是一個模塊的創建者,但作為模塊,它還提供了一個封裝解決方案。示例如下:
var ns = ns || {}, ns1 = ns1 || {}; // 模塊、命名空間創建者 var creator = function (val) { var val = val || 0; this.next = function () { return val ++ ; }; this.reset = function () { val = 0; } } creator.call(ns); // ns.next, ns.reset 此時已經存在 creator.call(ns1, 5000); // ns1包含相同的方法,但值被重寫為5000了 console.log(ns.next()); //0 console.log(ns1.next());//5000命名空間注入是用于為多個模塊或命名空間指定一個類似的功能基本集,但最好是在聲明私有變量或者方法時再使用它,其他時候使用嵌套命名空間已經足以滿足需要了。
7.自動嵌套的命名空間嵌套命名空間模式可以為代碼單元提供有組織的結構層級,但每次創建一個層級時,我們也得確保其有相應的父層級。當層級數量很大時,會給我們帶來很大的麻煩,我們不能快速便捷的創建想創建的層級。那么如何解決這個問題呢?Stoyan Stefanov提出,創建一個方法,其接收字符串參數作為一個嵌套,解析它,并自動用所需的對象填充基本名稱空間。下面是這種模式的一種實現:
function extend(ns, nsStr) { var parts = nsStr.split("."), parent = ns, pl; pl = parts.length; for (var i = 0; i < pl; i++) { // 屬性如果不存在,則創建它 if (typeof parent[parts[i]] === "undefined") { parent[prats[i]] = {}; } parent = parent[parts[i]]; } return parent; } // 用法 var myApplication = myApplication || {}; var mod = extend(myApplication, "module.module2");以前我們必須為其命名空間將各種嵌套顯式聲明為對象,現在用上述更簡潔、優雅的方式就實現了。
參考地址:JavaScript之命名空間模式 淺析
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/88935.html
摘要:前端日報精選第期寫給前端應屆生的職業規劃建議應用編譯優化之路進階篇命名空間模式解析源碼解析之任務管理入門教程快速上手聊聊改變歷史中文正式發布,帶來種新的圖表類型關系圖解好好寫代碼吧使用手冊掘金發布在即將全面支持掘金仿懂球帝 2017-10-10 前端日報 精選 【第1074期】寫給前端應屆生的職業規劃建議webpack 應用編譯優化之路JS進階篇--命名空間模式解析gulp源碼解析之任...
摘要:個人前端文章整理從最開始萌生寫文章的想法,到著手開始寫,再到現在已經一年的時間了,由于工作比較忙,更新緩慢,后面還是會繼更新,現將已經寫好的文章整理一個目錄,方便更多的小伙伴去學習。 showImg(https://segmentfault.com/img/remote/1460000017490740?w=1920&h=1080); 個人前端文章整理 從最開始萌生寫文章的想法,到著手...
摘要:模塊化是隨著前端技術的發展,前端代碼爆炸式增長后,工程化所采取的必然措施。目前模塊化的思想分為和。特別指出,事件不等同于異步,回調也不等同于異步。將會討論安全的類型檢測惰性載入函數凍結對象定時器等話題。 Vue.js 前后端同構方案之準備篇——代碼優化 目前 Vue.js 的火爆不亞于當初的 React,本人對寫代碼有潔癖,代碼也是藝術。此篇是準備篇,工欲善其事,必先利其器。我們先在代...
摘要:正在暑假中的課多周刊第期我們的微信公眾號,更多精彩內容皆在微信公眾號,歡迎關注。若有幫助,請把課多周刊推薦給你的朋友,你的支持是我們最大的動力。原理微信熱更新方案漲知識了,熱更新是以后的標配。 正在暑假中的《課多周刊》(第1期) 我們的微信公眾號:fed-talk,更多精彩內容皆在微信公眾號,歡迎關注。 若有幫助,請把 課多周刊 推薦給你的朋友,你的支持是我們最大的動力。 遠上寒山石徑...
閱讀 2985·2021-11-16 11:51
閱讀 2616·2021-09-22 15:02
閱讀 3732·2021-08-04 10:21
閱讀 3620·2019-08-30 15:43
閱讀 1955·2019-08-30 11:04
閱讀 3607·2019-08-29 17:14
閱讀 499·2019-08-29 12:16
閱讀 2942·2019-08-28 18:31