摘要:創建全局對象構造函數一個變量一個對象容器嵌套對象命名約定通常以全部大寫的方式來命名這個全局對象。在命名模式中,有一個全局對象,在沙箱模式中,有一個全局構造函數,我們這里命名為。
在javascript中,我們知道可以使用對象字面量或者構造函數創建對象,但是如何優雅地創建一個對象你卻不一定了解。
前人在踩過無數坑又填過無數坑之后,給我們總結了不同場景下的幾種對象創建模式:
命名空間模
模塊模式
沙箱模式
鏈模式
命名模式有這樣一種場景,假如你正在寫一個插件,這個插件內部會用到很多的全局變量,這時候你要怎么保證你的變量不會與其他插件的變量產生命名沖突呢?我們知道,在javascript中并沒有內置命名空間,后面的變量會覆蓋掉前面的變量,你要如何避免這種問題的發生?
可能你已經想到,只要足夠獨特的命名就可以了吧,比如lynneShowVar,這樣確實是可以的,但是如果變量很多,難道要為每個都起一個很獨特的命名?是不是很累?而且維護也是很麻煩的。
命名模式提出,為應用程序創建一個全局對象,比如MYAPP,然后將所有的變量和函數掛到這個全局對象(MYAPP)的屬性上。
//創建全局對象 var MYAPP = {}; //構造函數 MYAPP.parent = function () {}; MYAPP.child = function () {}; //一個變量 MYAPP.some_var = 1; //一個對象容器 MYAPP.modules = {} //嵌套對象 MYAPP.modules.module1 = {}; MYAPP.modules.module2 = {};
命名約定:通常以全部大寫的方式來命名這個全局對象。
優點:
避免代碼中的命名沖突
避免代碼與第三方的命名沖突
缺點
需要輸入更多字符
任何部分的代碼都可以修改全局實例
嵌套的額數字意味著更長的屬性查詢解析。
那么,有什么辦法可以避免這些缺陷么?聲明代碼依賴關系應該是一個不錯的主意了。
聲明依賴關系
var myFunction = function () { //依賴 var event = MYAPP.util.event, dom = MYAPP.util.dom; //... }
優點:
可讀性強
解析局部變量的速度總是比解析全局變量的速度快
減小代碼量
通用命名空間
隨著程序的復雜度的增加,如何保證全局對象上新添屬性不會覆蓋原有的屬性呢。這就需要每次在添加新屬性之前先檢查它是否已經存在了。
var MYAPP = MYAPP || {}; MYAPP.name = function (ns_string) { var parts = ns_string.split("."), parent = MYAPP, i; //剝離最前面的冗余全局變量 if (parts[0] === "MYAPP") { parts = parts.slice(1); } for(i = 0; i < parts.length; i++) { //如果不存在就創建一個屬性 if (typeof parent[parts[i]] === "undefined") { parent[parts[i]] = {}; } parent = parent[parts[i]]; } return parent; }
命名模式雖然好用,但還是有個問題,那就是任何部分的代碼都可以修改全局實例,以及里面的屬性,怎么避免?我們知道es5并沒有類的概念,如果要實現私有成員,可以使用閉包來 模擬這種特性。
模塊模式其實模塊模式是多種模式的組合
命名空間
即時函數
私有和特權函數
聲明依賴
MYAPP.ntilities.array = (function () { //依賴 var uobj = MYAPP.ntilities.object, ulang = MYAPP.ntilities.lang; //私有屬性 var array_string = "[object array]", ops = Object.prototype.toString; //私有方法 //... //其它 //共有API return { inArray: function (needle, haystack) { ... }, isArray: function (str) { ... } //更多... } })()
將全局變量導入到模塊中
可以將參數傳遞到包裝了模塊的即時函數中,有助于加速即時函數中全局符號的解析。
MYAPP.ntilities.array = (function (app, global) { }(MYAPP, this);沙箱模式
假設需要在同一個頁面運行同一個庫的兩個版本,很遺憾,前面兩種創建模式都是不支持的。這時候就需要模塊化。
在命名模式中,有一個全局對象 ,在沙箱模式中,有一個全局構造函數,我們這里命名為Sandbox()。這個構造函數可以接收一個或多個參數,這些參數指定對象實例需要的模塊名,以及一個回調函數。如:
//模塊名可以使用數組的形式傳參 Sandbox(["ajax", "dom"], function () { //這里是回調函數 }); //模塊名也可以使用單個參數的形式傳參,參數之間使用,號隔開 Sandbox("ajax", "dom", function () { //這里是回調函數 }); //不指定模塊名稱或指定"*",表示需要依賴所有模塊 Sandbox(function () { //這里是回調函數 }); Sandbox("*", function () { //這里是回調函數 });
在實現實際的構造函數之前,先為Sandbox添加一個名為modules的靜態屬性,這需要理解的是Sandbox同時也是一個對象。
Sandbox.modules = {}
把需要的模塊添加到Sandbox.modules對象中。假設我們一共需要dom、ajax、event模塊
Sandbox.modules.dom = function(box) { box.getElement = function () {}; }; Sandbox.modules.ajax = function(box) { box.getResponse = function () {}; }; Sandbox.modules.event = function(box) { box.attachEvent = function () {}; };
接下來實現構造函數
function Sandbox = function () { //將參數轉換成一個數組 var args = Array.prototype.slice.call(arguments), //最后一個參數是回調函數 callback = args.pop(), //args[0]如果是String類型,說明模塊作為多帶帶參數傳遞,否則模塊作為數組形式傳遞 modules = (args[0] && typeof args[0] === "String") ? args : arg[0], i; //確保該函數作為構造函數調用 if(!(this instanceof Sandbox)) { return new Sandbox (modules, callback); } //需要向this添加的屬性,也可能沒有,這里看實際項目需求 this.a = 1; this.b = 2; //現在向該核心"this"對象添加模塊 //不指定模塊名稱或指定"*",都表示制定所有模塊 if (!modules || modules === "*") { modules = []; for (i in Sandbox.modules) { modules.push[i]; } } //初始化所需的模塊 for(i = 0; i < modules.lenght; i++) { Sandbox.modules[modules[i]](this) } //依賴模塊已全部初始化,可以執行回調函數 callback(); } //獲取你還需要添加一些原型屬性,看需求 Sanndbox.prototype = { name: "MY Application", version: "1.0", getName: function () { return this.name; } };
優點
實現模塊化,解決 同一個頁面不能 使用同一個庫的不同版本的問題
優化了以點分割的名字的解析時間,如:MYAPP.untilities.array
鏈式模式鏈式模式可以使您能夠一個接一個地調用對象的方法,而無需將前一個操作返回的值付給變量,且無需分割成多行。如:
myobj.method1("hello").method2().method3("str");
這個很好理解,我們直接來看一看代碼
var obj = { al: 1, add: function (v) { this.val += v; return this; }, set: function (v) { this.val = v; return this; }, shout: function (v) { console.log(this.val); } }; //鏈方法調用 obj.add(1).set(2).shout();
可以看到,obj的每個方法都返回this對象,這就是實現鏈式的原理。
優點
節省輸入的字符
有助于分割函數,提高代碼的維護性
缺點
難以調試,一旦出現問題,難以定位到具體步驟
每種設計模式都各有優缺點,具體使用哪種模式還得看項目需求,大家一起學習吧。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85191.html
摘要:都是構造函數模式創建的原生構造函數。使用構造函數創建對象經歷了以下四個過程創建一個新對象構造函數的作用域交給新對象。 ??在創建對象的時候,使用對象字面量和 new Object() 構造函數的方式創建一個對象是最簡單最方便的方式。但是凡是處于初級階段的事物都會不可避免的存在一個問題,沒有普適性,意思就是說我要為世界上(程序中)的所有使用到的對象都使用一遍 var xxx = {} ,...
摘要:都是構造函數模式創建的原生構造函數。使用構造函數創建對象經歷了以下四個過程創建一個新對象構造函數的作用域交給新對象。 ??在創建對象的時候,使用對象字面量和 new Object() 構造函數的方式創建一個對象是最簡單最方便的方式。但是凡是處于初級階段的事物都會不可避免的存在一個問題,沒有普適性,意思就是說我要為世界上(程序中)的所有使用到的對象都使用一遍 var xxx = {} ,...
摘要:停更許久,近期計劃更新設計模式系列。單例模式是創建型設計模式的一種。雖然它不是正規的單例模式,但不可否認確實具備類單例模式的特點。適用場景單例模式的特點,意圖解決維護一個全局實例對象。 停更許久,近期計劃更新:設計模式系列。 showImg(https://segmentfault.com/img/bVbt7uw?w=800&h=600); 單例模式:限制類實例化次數只能一次,一個類只...
摘要:但是,這并不是采用單例的唯一原因。使用命名空間單例模式也被稱為模塊設計模式。函數內部聲明了一些局部函數和或變量。緊隨函數聲明放置即可立即執行外部函數,并將所得的對象文字費賠給變量。 JavaScript設計模式-第一部分:單例模式、組合模式和外觀模式 設計模式是一些可靠的編程方式,有助于保證代碼更加易于維護、擴展及分離,所有設計模式在創建大型JavaScript應用程序時均不可或缺 單...
摘要:此時我們創建的對象內保存靜態變量通過取值器訪問,最后將這個對象作為一個單例放在全局空間里面作為靜態變量單例對象供他人使用。 單例模式 又被稱為單體模式,是只允許實例化一次的對象類。有時我們也用一個對象來規劃一個命名空間,井井有條的管理對象上面的屬性和方法。 傳統的面向對象語言中單例模式的實現,均是單例對象從類中創建而來,在以類為中心的語言中,這是很常見的做法。如果需要某個對象,就必須先...
摘要:三種使用構造函數創建對象的方法和的作用都是在某個特殊對象的作用域中調用函數。這種方式還支持向構造函數傳遞參數。叫法上把函數叫做構造函數,其他無區別適用情境可以在特殊的情況下用來為對象創建構造函數。 一、工廠模式 工廠模式:使用字面量和object構造函數會有很多重復代碼,在此基礎上改進showImg(https://segmentfault.com/img/bVbmKxb?w=456&...
閱讀 2907·2021-10-19 10:09
閱讀 3126·2021-10-09 09:41
閱讀 3371·2021-09-26 09:47
閱讀 2687·2019-08-30 15:56
閱讀 590·2019-08-29 17:04
閱讀 979·2019-08-26 11:58
閱讀 2505·2019-08-26 11:51
閱讀 3353·2019-08-26 11:29