javaScript設計模式之面向對象編程(object-oriented programming,OOP)(一)
面試的時候,總會被問到,你對javascript面向對象的理解?
面向對象編程(object-oriented programming,OOP)是一種程序設計範型。它講對象作為程序的設計基本單元,講程序和數據封裝其中,以提高程序的重用性、靈活性和擴展性。
一、舉個例子
有這麽一個需求:做一個驗證表單功能,僅需要驗證用戶名,郵箱,密碼等
覺得在項目產品開發中,自己是這麽寫的
function checkName(){ //驗證姓名 } function checkEmail(){ //驗證郵箱 } function checkPassword(){//驗證碼密碼 }
聲明了3個全局變量,
下面是創建3個函數保存在變量裏來實現你的功能,而你寫的是將你的變量名放在function後邊,也代表了你的變量,所以聲明了3個全局變量。
//創建了3個函數保存在變量裏 var checkName = function(){ //驗證姓名 } var checkEmail = function(){ //驗證碼郵箱 } var checkPassword = function(){ //驗證密碼 }
從功能上講沒有任何問題,但是如果別人也定義了同樣的方法就會覆蓋原有的功能,這種相互覆蓋的問題不易覺察到。
我們可以將這些檢查函數放在一個變量裏保存,這樣減少覆蓋和被覆蓋的風險。
(1)用對象收編變量
對象,他有屬性和方法,我們訪問屬性或者方法,可以通過點語法向下遍歷查詢得到,我們可以創建一個檢測對象,我們把方法放在裏面。
var CheckObject = { checkName:function(){ //驗證姓名 }, checkEmail:function(){ //驗證郵箱 }, checkPassword:function(){ //驗證密碼 } }
這個時候我們將所有的函數作為CheckObject對象的方法,這樣我們就只有一個對象,比如檢測姓名CheckObject.checkName().
(2)對象的另一種形式
首先聲明一個對象,然後給他添加方法,在JavaScript中函數也是對象。
var CheckObject = function(){}; CheckObject.checkName = function(){ //驗證姓名 } CheckObject.checkEmail = function(){ //驗證郵箱 } CheckObject.checkPassword = function(){ //驗證密碼 }
但是當別人想用你寫的對象方法就比較麻煩,因為這個對象不能復制一份(這個對象類在用new關鍵字創建新的對象時,新創建的對象時不能繼承這些方法)
(3)真假對象
如果想簡單的復制一下,你可以將這些方法放在一個函數對象中。
var CheckObject = function(){ return { checkName = function(){ //校驗姓名 }, checkEmail = function(){ //校驗郵箱 } checkPassword = function(){ //校驗密碼 } } }
當每次調用這個函數的時候,把我們之前的對象返回出來,當別人每次調用這個函數時都會返回新對象。這樣我們每個人使用的時候就不會相互影響,比如檢測郵箱可以這樣:
var a = CheckObject(); a.checkEmail();
(4)類也可以
雖然通過創建新對象完成需求,但是他不是一個真正的意義上的類的創建方式,並且創建對象a和對象CheckObject沒有任何關系,返回的對象與CheckObject對象無關,稍微優化一下。
var CheckObject = function(){ this.checkName = function(){ //驗證姓名 } this.checkEmail = function(){ //驗證郵箱 } this.checkPassword = function(){ //驗證密碼 } }
上面的這樣的對象,就可以看成是類,我們就可以不需要使用創建對象方法創建,既然是一個類,就用關鍵詞new來創建
var a = new CheckObject(); a.checkEmail();
這樣就可以用CheckObject類創建出來對象,我們其他人就可以對類實例化(用類創建對象),這樣每一個人都有一套自己的方法。
(5)一個檢測類
通過this的定義,每一次通過new關鍵字創建新對象時候,新創建的對象都會對類的this上的屬性進行復制,所以新創建的對象都會有自己的一套方法,然而有時候造成消耗很奢侈,我們需要處理一下。
var CheckObject = function(){}; CheckObject.prototype.checkName = function(){ //驗證姓名 } CheckObject.prototype.checkEmail = function(){ //驗證郵箱 } CheckObject.prototype.checkPassword = function(){ //驗證密碼 }
這樣創建對象實例時候,創建出來的對象所擁有的方法都是一個,因為他們需要依賴prototype原型依次尋找,而找到方法是同一個,但是prototype寫很多遍,可以這麽寫
var CheckObject = function(){}; checkObject.prototype = { checkName:function(){ //驗證姓名 }, checkEmail:function(){ //驗證郵箱 }, checkPassword:function(){ //驗證密碼 } }
以上兩種方法不能混著用。
如在後邊為對象的原型對象賦值新對象,那麽會覆蓋之前對prototype對象賦值的方法。
var a = new CheckObject(); a.checkName(); a.checkEmail(); a.checkPassword();
(6)方法還可以這樣用
1、this對象
var CheckObject = { checkName:function(){ //驗證姓名 return this; }, checkEmail:function(){ //驗證郵箱 return this; }, checkPassword:function(){ //驗證密碼 return this; } }
使用:
CheckObject.checkName().checkEmail().checkPassword();
2、類的原型對象
var CheckObject = function(){}; CheckObject.prototype = { checkName:function(){ //驗證姓名 return this; }, checkEmail:function(){ //驗證郵箱 return this; }, checkPassword:function(){ //驗證密碼 return this; } }
但是使用的時候需要創建一下
var a = new CheckObject(); a.checkName().checkEmail().checkPassword();
(7)函數祖先
比如你想給每一個函數都添加一個檢測郵箱的方法。
Function.prototype.checkEmail = function(){ //檢測郵箱 }
這樣使用這個方法就比較簡單,
1、函數形式
var f = function(){}; f.checkEmail();
2、類的形式
var f = new Function(); f.checkEmail();
你這種方式,原則上沒有問題,但是汙染了全局原生對象Function,這樣別人創建的函數也會被你創建的函數汙染,造成不必要的開銷,但是你可以抽象出一個統一添加方法的功能方法。方法如下:
Function.prototype.addMethod = function(name,fn){ this[name] = fn; }
這個時候,如果你想添加郵箱驗證的方法和姓名驗證的方法,可以這樣使用
var methods = function(){};
//或者
var methods = new Function();
methods.addMethod(‘checkName‘,function(){
//驗證姓名
})
methods.addMethod(‘checkEmail‘,function(){
//驗證郵箱
})
methods.checkName();
methods.checkEmail();
(8)鏈式添加
如果想鏈式添加,在addMethods中將this返回,就可以
Function.prototype.addMethod = function(name,fn){ this[name] = fn; return this; }
如果你還想添加方法,可以這樣:
var methods = function(){}; methods.addMethod(‘checkName‘,function(){ //驗證姓名 }).addMethod(‘checkEmail‘,function(){ //驗證郵箱 });
如果我想鏈式使用,應該如何實現?
既然添加方法可以將this返回實現,那麽添加的每一個方法都將this返回是不是也就實現了呢?
var methods = function(){}; methods.addMethod(‘checkName‘,function(){ //驗證姓名 return this; }).addMethod(‘checkEmail‘,function(){ //驗證郵箱 return this; })
測試一下:
methods.checkName().checkEmail();
(9)換一種使用方式
1、函數式調用
Function.prototype.addMethod = function(name,fn){ this[name] = fn; return this; }
2、類式調用
Function.prototype.addMethod = function(name,fn){ this.prototype[name] = fn; return this; }
使用類式調用,不能直接使用,需要通過new關鍵字來創建新對象
var m = new Methods(); m.checkEmail();
JavaScript中函數時一等公民。
1、如何實現方法的鏈式調用?
只需在類中的每個方法中通過this關鍵字返回對象實例的引用。每次函數調用都會返回一個新對象,表面上是CheckObject對象,實際是返回的新對象,這樣每次調用就不會相互影響了。
2、為函數添加多個方法的addMethod方法?
(1)this對象
var CheckObject = { checkName: function(){ //驗證姓名 return this; } ,
checkEmail: function(){
//驗證郵箱
return this;
} ,
checkPassword: function(){ //驗證密碼 return this; } ,
}
(2)類的原型對象
var CheckObject = function(){}; CheckObject.prototype = { checkName:function(){ //驗證姓名 return this; } , checkEmail:function(){ //驗證郵箱 return this; }, checkPassword:function(){ //驗證密碼 return this; } }
javaScript設計模式之面向對象編程(object-oriented programming,OOP)(一)