一 命名空間模式數組
1 命名空間模式的代碼格式閉包
var MYAPP={ name:"", version:"1.0", init:function(){ } };
2 命名空間的優勢:dom
減小全局變量的數量, 函數
避免命名衝突
工具
3 缺點: this
須要輸入更多的字符,每一個函數和變量前面都須要附加前綴
長嵌套名字須要更多的解析查詢時間
var a=""; function addPerson(){ } function someVar=""; //上面有三個全局變量a ,addPerson,someVar //若是使用命名空間模式,能夠減縮微一個變量 var MYAPP={ a:"", addPerson:function(){}, someVar:"" }; /* 按照公約,全局變量所有大寫, 優勢: 避免命名衝突, 避免與第三方的代碼衝突 缺點: 須要輸入更多的字符,每一個函數和變量前面都須要附加前綴 長嵌套名字須要更多的解析查詢時間 */
1.1 通用命名空間函數 spa
當使用命名空間的時候,咱們一般檢查一下該命名空間是否存在,以避免給覆蓋了(當代碼被分割爲多個文件或者部分的時候),通常格式以下:prototype
var MYAPP=MYAPP||{};
code
可是若是嵌套的層數比較多,檢查的代碼就會不少,下面給出一種通用的命名空間檢查的函數對象
/*在建立一個命名空間的時候,首先檢查它是否已經存在*/ var MYAPP=MYAPP||{}; //須要檢查5次,這太煩了,下面給出一個通用的函數進行檢查 MYAPP.module1.module2.module3.module4.module5={}; /*在建立一個命名空間的時候,首先檢查它是否已經存在*/ var MYAPP=MYAPP||{}; MYAPP.namespace=function(ns){ var parts=ns.split("."), parent=MYAPP, i, len; if(parts[0]==="MYAPP"){ parts=parts.slice(1); } for(i=0,len=parts.length;i<len;i++){ if(typeof parent[parts[i]]==="undefined"){ parent[parts[i]]={}; } parent=parent[parts[i]]; } return parent; }; MYAPP.namespace("MYAPP.module1.module2.module3.module4.module5");
二 聲明依賴關係
因爲咱們上面提到了使用命名空間的方法,各個命名空間之間可能會有依賴,
例如咱們應用到頁面中,可能要依賴DOM模塊和Event模塊(YAHOO.util.Dom和YAHOO.util.Event),
若是在咱們的模塊中,始終使用YAHOO.util.Dom和YAHOO.util.Event這兩個變量,有如下不足:
1 壓縮代碼的時候,這兩個不能壓縮,
2 長嵌套要花更多的時間解析
3 寫的時候也麻煩
因此咱們來聲明一下須要依賴的模塊,將全局變量改成局部變量
var myFun=function(){ var event=YAHOO.util.Event, dom=YAHOO.util.Dom; //event..... //dom..... };
聲明依賴關係的優勢:
1 聲明依賴關係,位於函數的頭部,所以更清晰的看到咱們所依賴的模塊
2 解析局部變量比解析全局變量速度要快
3 能夠將局部變量進行壓縮,減小代碼量
三 私有屬性和方法
js沒有私有,保護等屬性和方法,js中全部的屬性和方法都是公共的,可是咱們能夠利用閉包來實現私有屬性和私有方法
3.1 私有成員
「閉包」(closure):可以讀取其餘函數內部變量的函數。因爲在Javascript語言中,只有函數內部的子函數才能讀取該函數的局部變量,所以能夠把閉包簡單理解成「定義在一個函數內部的函數」。
/* *可以讀取到其餘函數(addPerson)內部的變量(name)的函數(getName) */ function addPerson(){ var name1="Jhon"; this.getName=function(){ return name1; }; } var onePerson=new addPerson(); console.log(onePerson.name1);//undefined console.log(onePerson.getName())//"Jhon" console.log(name1);//ReferenceError: name1 is not defined
3.2 特權方法
特權方法:能夠訪問到私有成員的公共方法,上面demo中的getName就是特權方法
3.3 私有性失效
當特權方法返回的是一個對象或者數組的時候,其實返回的是對象或者數組的引用(地址),這樣的話就破壞了該對象或者數組的私有性
解決方案:1 最低受權原則,即不給予超過須要的特權,例以下面的例子中,咱們只返回colors的第幾個元素,colors[2],這樣的話就不會改變colors,可是這種方法侷限性太大
2 使用一個深度拷貝的函數,將數組或者對象裏面的值進行復制,給一個新的變量,返回這個新的變量便可,會在下一章詳細介紹
function addPerson(){ var colors=["red","black","blue","green"]; this.getColors=function(){ return colors;//這裏傳遞是colors數組的引用,即地址 }; } var onePerson=new addPerson(); var newColors=onePerson.getColors();//這裏newColors的值是私有屬性colors的地址 newColors[2]="white"; console.log(onePerson.getColors());// ["red", "black", "white", "green"]
3.4 對象字面量以及私有性
上面咱們提到了函數的私有屬性和特權方法,這裏咱們看一下對象字面量的私有屬性和特權方法------模塊模式
var myobj=(function(){ var name="Jhon"; return { getName:function(){ return name; } }; }()); console.log(myobj.getName());//Jhon
3.5 原型和私有性
當將私有成員與構造函數一塊兒使用的時候,其中一個缺點就是每次建立實例的時候,這些私有成員都會被建立,爲了不復制工做節省內存,咱們將公用的屬性和方法添加到構造函數的prototype屬性中
優勢:
1 多個實例共享公見的數據,
2 隱藏的私有成員
/* *其中name是每一個實例的私有變量 *version雖然也是每一個實例的私有變量,可是又是它們公用的 *因此能夠放到原型裏 *可是name不能夠,由於每一個實例的name值都不同 */ function addPerson(name){ this.getName=function(){ return name; }, this.setName=function(newName){ name=newName; } } addPerson.prototype=(function(){ var version="1.0"; return { getVersion:function(){ return version; }, setVersion:function(newVersion){ version=newVersion; } }; }()); var p1=new addPerson("Jhon"); var p2=new addPerson("Amy"); console.log(p1.name);//undefined name是實例的私有成員,外面訪問不到 console.log(p1.getName());//Jhon 只能經過特權方法來訪問 console.log(p2.name);//undefined name是實例的私有成員,外面訪問不到 console.log(p2.getName());//Amy 只能經過特權方法來訪問 console.log(p1.version);//undefined version也是實例的私有成員,可是是全部實例公用的 console.log(p1.getVersion());//1.0 也只能經過特權方法來訪問 /* 這裏只要一個實例改變了全部實例公用的私有成員version 全部的成員的這個值都會改變 */ console.log(p1.setVersion("1.1")); console.log(p1.getVersion());//1.1 console.log(p2.getVersion());//1.1 /* 可是每一個實例的私有成員發生改變的話,不會影響到其餘成員 */ console.log(p1.setName("Green")); console.log(p1.getName());//Green console.log(p2.getName());//Amy
3.6 將私有方法揭示爲公共方法-----揭示模式
將私有方法暴露爲公共方法,當把多個功能放置在一個函數時,最好使用該方法,這樣若是其中一個功能發生意外,也不會影響其餘功能繼續使用該私有方法
例以下面的例子,將查看元素在一個數組中的位置以及查看一個元素是否位於一個數組兩個功能都放置在indexOf函數,使用下面的揭示模式,若是其中一個功能被修改,也不會影響另一個的繼續使用
/* 最重要的是,若是其中一個暴露出來的方法(indexOf)出了問題,也不會影響使用同一個私有方法(indexOf)的公共方法(inArray)的使用 */ var myarray; (function(){ var str="[object Array]", toString=Object.prototype.toString; //驗證是否爲數組 function isArray(a){ return toString.call(a)===str; } //找到該元素在數組中的位置 function indexOf(hayStack,needle){ var i=0, max=hayStack.length; for(;i<max;i++){ if(hayStack[i]==needle){ return i; } } return -1; } //揭示模式,將函數內部的私有方法(isArray和indexOf)暴露成爲公共方法 myarray={ isArray:isArray, indexOf:indexOf, inArray:indexOf }; })(); console.log(myarray.isArray([1,2]));//true console.log(myarray.indexOf([1,2],3));//-1 console.log(myarray.inArray([1,2],2));//1 myarray.indexOf=null; console.log(myarray.inArray([1,2],2));//1 console.log(myarray.indexOf([1,2],2));//報錯
四 模塊模式
模塊模式提供了一種建立自包含非耦合代碼片斷的有利工具,能夠將它視爲黑盒功能,而且能夠根據您所編寫軟件的需求進行添加/替換或者刪除這些模塊
模塊模式是如下模式的組合:
命名空間
即時函數
私有和特權成員
聲明依賴
4.1 揭示模塊模式
/*命名空間*/ var MYAPP=MYAPP||{}; MYAPP.namespace=function(ns){ var parts=ns.split("."), parent=MYAPP, i, len; if(parts[0]==="MYAPP"){ parts=parts.slice(1); } for(i=0,len=parts.length;i<len;i++){ if(typeof parent[parts[i]]==="undefined"){ parent[parts[i]]={}; } parent=parent[parts[i]]; } return parent; }; MYAPP.namespace("MYAPP.utilities.array"); //(function(){})()即時函數 MYAPP.utilities.array=(function(){ //聲明依賴,這個demo沒有使用到,可是模塊模式能夠包含該模式 var uobj=MYAPP.utilities.object, ulang=MYAPP.utilities.lang, str="[object Array]",//私有屬性 toString=Object.prototype.toString;//私有屬性 //私有方法 function isArray(a){ return toString.call(a)===str; } //私有方法 function indexOf(hayStack,needle){ var i=0, max=hayStack.length; for(;i<max;i++){ if(hayStack[i]==needle){ return i; } } return -1; } //特權成員,公有的API,將私有方法揭示爲公共方法---揭示模式 return { isArray:isArray, indexOf:indexOf, inArray:indexOf }; })(); console.log(MYAPP.utilities.array.isArray([1,2]));//true console.log(MYAPP.utilities.array.indexOf([1,2],3));//-1 console.log(MYAPP.utilities.array.inArray([1,2],2));//1
4.2 建立構造函數的模式:與4.1的揭示模式的區別,就是返回值不一樣,揭示模式返回的是一個對象,建立構造函數模式返回的是一個函數
/*命名空間*/ var MYAPP=MYAPP||{}; MYAPP.namespace=function(ns){ var parts=ns.split("."), parent=MYAPP, i, len; if(parts[0]==="MYAPP"){ parts=parts.slice(1); } for(i=0,len=parts.length;i<len;i++){ if(typeof parent[parts[i]]==="undefined"){ parent[parts[i]]={}; } parent=parent[parts[i]]; } return parent; }; MYAPP.namespace("MYAPP.utilities.array"); //(function(){})();即時函數 MYAPP.utilities.array=(function(){ //聲明依賴,這個demo沒有使用到,可是模塊模式能夠包含該模式 var uobj=MYAPP.utilities.object, ulang=MYAPP.utilities.lang, Constr; Constr=function(o){ this.elements=this.toArray(o); }; Constr.prototype={ constructor:MYAPP.utilities.array, version:"1.0", toArray:function(obj){ for(var i=0,a=[],len=obj.length;i<len;i+=1){ a[i]=obj[i]; } return a; } }; return Constr; })();//將全局變量導入到模塊中 var obj=[1,2,34]; var a=new MYAPP.utilities.array(obj); a.version;//"1.0"
五 沙箱模式
沙箱模式能夠解決命名空間模式的幾個缺點:
1 在命名空間模式中是沒有辦法使用同一個庫的兩個版本在一個頁面使用的,由於咱們都要使用全局變量MYAPP
2 對於以.分割的名稱來講,須要更長的解析時間,例如MYAPP.utilities.array
沙箱是提供了一個可用於模塊運行的環境,且不會對其餘模塊和其餘的沙箱形成任何影響
六 靜態成員
七 對象常量
八 鏈模式
九 method方法