所謂代碼,當你隨便命名一個變量:var name = "ukerxi"; 就是一句代碼;但當你的代碼寫出來后,對於后續維護及閱讀的人,就可以看出代碼是否,易讀,易理解;優雅的代碼總是遵守一定的規范,這篇文章就說說幾種命名空間的運用,運用好了,可以有利於多人開發,模塊化代碼,代碼解耦有一定的作用!
先來看看一個錯誤的示范:
// 定義一些數據 var name = "ukerxi"; var version = "1.0.0"; var hobby = "riding"; sessionStorage.data = 'test'; sessionStorage.text = 'test'; sessionStorage.name = 'test';
利用命名空間進行重構:
var men = { name: 'ukerxi', version: '1.0.0', hobby: 'riding' } // 由於 sessionStorage 只支持字符型的數據,所以必須將數據進行JSON化處理 sessionStorage.message = JSON.stringify({ data: 'test', text: 'test', name: 'test', });
重構后只產生了兩個全局變量,減少了命名沖突的概率,對於全局變量的使用,必須盡量減少,特別是單頁面開始時;而sessionStorage等本地存儲的使用更加注意,由於它們在多頁面之間可以互相訪問,很容易造成命名沖突;一下更具體的介紹幾種命名空間的使用:
一、使用單例對象進行包裹(單例模式)
var myObj = { name: "ukerxi" }; myObj.fn = function{ // do something };
多人開發時,可以根據自己的名字進行命名一個對象,然后自己寫的變量及函數都放進這個命名空間中,這樣就避免與他人沖突;在實際開發時,還會遇到多個文件之間共享一個命名空間,可以使用命名空間檢測,避免重復或覆蓋;例如:
// 方法一 if (typeof myObj === "undefined") { var myObj = {}; } // 方法二(推薦) var myObj = myObj || {};
當你只是想對一個命名空間進行擴展,形如,對插件進行擴展,在JQuery.extend() 方法的擴展;
var myObj=(function(o){ o.addFn = ""; // 實現擴展屬性功能 return o; })(window.myObj || {}); // 必須或上空對象,以便在沒有事先聲明而使用引起的錯誤
二、閉包實現變量的包裹,減少全局變量
var myObj = (function () { // 私有變量 var name = "ukerxi"; // 返回get方法 return { getName: function () { return name; } }; }()); // 可以變通成更加通用的命名空間 var commonObject = (function(){ var _data = { name: "ukerxi", version: "1.0" } //返回get/set方法 return { get: function(key){ return _data[key]; }, set: function(key, value){ // 檢測是否存在要設置的值在不在原本的數據中,這樣做是不添加新數據 //如果要添加新數據,這句可以不加 if(typeof _data[key] != "undefined"){ _data[key] = value; }else{ return false; } } } }());
通過返回的getter、setter方法進行讀取及設置值,這樣就不用擔心變量命名沖突;
三、使用構造函數&原型方法,可以構造出更加強大的命名空間
function CommonObj(name) { // 私有變量 // 此處可以不用定義內部的_name變量,因為參數也是私有變量 var _name = name; // 公用方法 this.getName = function () { return _name; }; } CommonObj.prototype = (function () { //靜態私有變量,所有實例方法共享這個數據 var _static = "static"; // return { getStatic: function () { return _static; } }; }()); var newObj1 = new CommonObj("obj1"); var newObj2 = new CommonObj("obj2"); // 測試輸出 console.log(newObj1.getName()); // -- "obj1" console.log(newObj2.getName()); // -- "obj2" console.log(newObj1.getStatic); // -- "static" console.log(newObj2.getStatic); // -- "static"
最終每次實例化 CommonObj 構造函數時可以進行賦值,然而原型上的屬性是共享的;上面代碼看起來還是分散的,可以進一步進行改進;
var CommonObj = (function () { // 靜態私有變量 var _static = ""; function _fn(name) { // 公用方法 this.getName = function () { return name; }; } // 定義原型方法 _fn.prototype ={ getStatic: function () { return _static; } } // 返回真正的構造函數 return _fn; }()); var newObj1 = new CommonObj(); var newObj2 = new CommonObj(); // 測試輸出 console.log(newObj1.getName()); // -- "obj1" console.log(newObj2.getName()); // -- "obj2" console.log(newObj1.getStatic); // -- "static" console.log(newObj2.getStatic); // -- "static"
四、函數的靜態調用與非靜態調用
主要特性是,通過類自身定義的屬性是不會被實例化函數擁有及繼承的,故也可以看做是一種命名空間,后續結合設計模式的“建造者”模式,可以創造出強大的一種運用形式;
// 構造函數 var MyObj = function (name) { this.name = name; }; // 靜態方法 MyObj.getName = function () { console.log("test"); }; // 原型方法 MyObj.prototype.getName = function () { console.log(this.name); }; // 靜態調用 MyObj.getName(); // "test" // 實例化調用 var fn = new MyObj("ukerxi"); fn.getName(); // ukerxi 一種特別的自執行方式形成的命名
五、最后再介紹一種特別的自執行方式形成的命名空間
var CommonObj = ({ fn: function() {console.log("test");}, name: "ukerxi", init: function(){ console.log(this.name); return this; } }).init();
上面例子相當於新建一個對象,然后執行 init方法,最后返回 this 指向這個對象,最后CommonObj 就包含了新建對象的引用;當然實際運用中不建議這樣用,只是用來裝大神的;
【結束語】
系列文章,包括了原創,翻譯,轉載等各類型的文章;一方面是為了自己總結,另一方面頁希望可以共享知識;在技術方面有輸入,也要有所輸出,才能更進一步!文章基於自己的實踐、閱讀及理解,如有不合理及錯誤的地方,煩請各大佬評論指出,以便改正,感謝!
