[js高手之路]javascript物件導向的常見寫法與優缺點
我們透過表單驗證的功能,來逐步演進物件導向的方式. 對於剛剛接觸javascript的朋友來說,如果要寫一個驗證使用者名稱,密碼,郵箱的功能, 一般可能會這麼寫:
1 //表單驗證
2 var checkUserName = function(){
3 console.log( '全域性checkUserName' );
4 };
5 var checkUserEmail = function(){
6 console.log( '全域性checkUserEmail' );
7 };
8 var checkUserPwd = function(){
9 console.log( '全域性checkUserPwd' );
10 };
這種寫法,從功能上來說 沒有什麼問題, 但是在團隊協作的時候, 會造成覆蓋全域性變數的問題, 那要大大降低覆蓋的可能性, 一般會在外面套一個物件
1 var Utils = {
2 checkUserName : function(){
3 console.log( 'Utils->checkUserName' );
4 },
5 checkUserEmail : function(){
6 console.log( 'Utils->checkUserEmail' );
7 },
8 checkUserPwd : function(){
9 console.log( 'Utils->checkUserPwd' );
10 }
11 }
12
13 checkUserEmail();
14 Utils.checkUserEmail();
上面這種方式,是字面量方式新增,在設計模式裡面,也稱為單例(單體)模式, 與之類似的可以透過在函式本身新增屬性和方法,變成靜態屬性和方法,達到類似的效果:
1 var Utils = function(){
2
3 }
4 Utils.checkUserName = function(){
5 console.log( 'Utils.checkUserName' );
6 }
7 Utils.checkUserPwd = function(){
8 console.log( 'Utils.checkUserPwd' );
9 }
10 Utils.checkUserEmail = function(){
11 console.log( 'Utils.checkUserEmail' );
12 }
13
14 Utils.checkUserEmail();
15
16 for( var key in Utils ){
17 ( Utils.hasOwnProperty( key ) ) ? console.log( key ) : '';
18 }
19
20 //加在函式上面的屬性和方法,無法透過物件使用
21 var oUtil = new Utils();
22 oUtil.checkUserEmail();//錯誤
還可以透過函式呼叫方式,返回一個物件,把方法和屬性寫在物件中, 這種方式 跟物件導向沒有什麼關係,只是從函式的返回值角度來改造
1 //使用函式的方式 返回一個物件
2 var Util = function(){
3 return {
4 checkUserName : function(){
5 console.log( 'userName...' );
6 },
7 checkUserPwd : function(){
8 console.log( 'userPwd...' );
9 },
10 checkUserEmail : function(){
11 console.log( 'userEmail...' );
12 }
13 }
14 }
15 Util().checkUserEmail();
還可以透過類似傳統面嚮物件語言,使用建構函式方式 為每個例項新增方法和屬性, 這種方式,存在一個問題, 不能達到函式共用,每個例項都會複製到方法.
1 var Util = function(){
2 this.checkUserName = function(){
3 console.log('userName');
4 };
5 this.checkUserEmail = function(){
6 console.log('userEmail');
7 };
8 this.checkUserPwd = function(){
9 console.log('userPwd');
10 };
11 }
12
13 var oUtil1 = new Util();
14 var oUtil2 = new Util();
15 console.log( oUtil1.checkUserEmail === oUtil2.checkUserEmail );//false
一般,我們可以透過原型屬性(prototype)改造這種方式,達到不同例項共用同一個方法
1 var Util = function(){
2
3 };
4 Util.prototype.checkUserName = function(){
5 console.log('userName');
6 };
7 Util.prototype.checkUserPwd = function(){
8 console.log('userPwd');
9 };
10 Util.prototype.checkUserEmail = function(){
11 console.log('userEmail');
12 };
13 var oUtil1 = new Util();
14 var oUtil2 = new Util();
15 console.log( oUtil1.checkUserEmail === oUtil2.checkUserEmail );//true
也可以把原型物件上的所有方法,使用字面量方式簡寫
1 var Util = function(){
2
3 };
4 Util.prototype = {
5 checkUserEmail : function(){
6 console.log( 'userEmail' );
7 },
8 checkUserName : function(){
9 console.log( 'userName' );
10 },
11 checkUserPwd : function(){
12 console.log( 'userPwd' );
13 }
14 };
15 var oUtil1 = new Util();
16 var oUtil2 = new Util();
17 console.log( oUtil1.checkUserEmail === oUtil2.checkUserEmail );//true
注意: 字面量方式和原型物件一個個新增 這兩種不要混用, 否則會產生覆蓋
如果我們想把物件導向的使用方式更加的優雅,比如鏈式呼叫, 我們應該在每個方法中返回物件本身,才能繼續呼叫方法, 即返回this
1 var Util = function(){
2 return {
3 checkUserName : function(){
4 console.log( 'userName...' );
5 return this;
6 },
7 checkUserPwd : function(){
8 console.log( 'userPwd...' );
9 return this;
10 },
11 checkUserEmail : function(){
12 console.log( 'userEmail...' );
13 return this;
14 }
15 }
16 }
17 // 方法中如果沒有返回this,下面這種呼叫方式是錯誤的
18 Util().checkUserEmail().checkUserName();
19
20 // 方法中返回物件本身,可以鏈式呼叫
21 Util().checkUserEmail().checkUserName().checkUserPwd();
1 var Util = function(){
2 this.checkUserName = function(){
3 console.log('userName');
4 return this;
5 };
6 this.checkUserEmail = function(){
7 console.log('userEmail');
8 return this;
9 };
10 this.checkUserPwd = function(){
11 console.log('userPwd');
12 return this;
13 };
14 }
15
16 new Util().checkUserEmail().checkUserName().checkUserPwd();
var Util = function(){
};
Util.prototype = {
checkUserEmail : function(){
console.log( 'userEmail' );
return this;
},
checkUserName : function(){
console.log( 'userName' );
return this;
},
checkUserPwd : function(){
console.log( 'userPwd' );
return this;
}
};
new Util().checkUserEmail().checkUserName().checkUserPwd();
1 var Util = function(){
2
3 };
4 Util.prototype.checkUserName = function(){
5 console.log('userName');
6 return this;
7 };
8 Util.prototype.checkUserPwd = function(){
9 console.log('userPwd');
10 return this;
11 };
12 Util.prototype.checkUserEmail = function(){
13 console.log('userEmail');
14 return this;
15 };
16
17 new Util().checkUserEmail().checkUserName().checkUserPwd();
在實際開發中,我們經常需要擴充套件一些功能和模組。擴充套件可以在本物件或者父類物件或者原型上
1 Function.prototype.checkUserName = function(){
2 console.log('ghostwu');
3 };
4
5 var fn1 = function(){};
6 var fn2 = function(){};
7
8 console.log( 'checkUserName' in fn1 ); //true
9 console.log( 'checkUserName' in fn2 ); //true
10
11 fn1.checkUserName(); //ghostwu
12 fn2.checkUserName(); //ghostwu
如果我們使用上面這種方式擴充套件,從功能上來說,是沒有問題的,但是確造成了全域性汙染:通俗點說,並不是說有的函式都需要checkUserName這個方法,而我們這樣寫,所有的函式在建立過程中都會從父類的原型鏈上繼承checkUserName, 但是這個方法,我們根本不用, 所以浪費效能, 為了解決這個問題,我們應該要在需要使用這個方法的函式上新增,不是所有的都新增,另外關於in的用法,如果不熟悉,可以看下我的這篇文章:立即表示式的多種寫法與注意點以及in運算子的作用
1 Function.prototype.addMethod = function( name, fn ){
2 this[name] = fn;
3 }
4
5 var fn1 = function(){};
6 var fn2 = function(){};
7
8 fn1.addMethod( 'checkUserName', function(){console.log('ghostwu');});
9
10 fn1.checkUserName(); //ghostwu
11 fn2.checkUserName(); //報錯
透過上述的改造,成功解決了全域性汙染, fn2這個函式上面沒有新增checkUserName這個方法,只在fn1上面新增
我們繼續把上面的方式,改成鏈式呼叫: 這裡需要改兩個地方, 一種是新增方法addMethod可以鏈式新增, 一種是新增完了之後,可以鏈式呼叫
1 Function.prototype.addMethod = function( name, fn ){
2 this[name] = fn;
3 return this;
4 };
5
6 var fn1 = function(){};
7
8 fn1.addMethod( 'checkUserName', function(){
9 console.log( 'userName:ghostwu' );
10 return this;
11 } ).addMethod( 'checkUserEmail', function(){
12 console.log( 'userEmail' );
13 return this;
14 } ).addMethod( 'checkUserPwd', function(){
15 console.log( 'userUserPwd' );
16 return this;
17 } );
18 fn1.checkUserName().checkUserEmail().checkUserPwd();
上面是屬於函式式 鏈式 呼叫, 我們可以改造addMethod方法, 在原型上新增函式,而不是例項上, 這樣我們就可以達到類式的鏈式呼叫
1 Function.prototype.addMethod = function( name, fn ){
2 this.prototype[name] = fn;
3 return this;
4 };
5
6 var fn1 = function(){};
7
8 fn1.addMethod( 'checkUserName', function(){
9 console.log( 'userName:ghostwu' );
10 return this;
11 } ).addMethod( 'checkUserEmail', function(){
12 console.log( 'userEmail' );
13 return this;
14 } ).addMethod( 'checkUserPwd', function(){
15 console.log( 'userUserPwd' );
16 return this;
17 } );
18 new fn1().checkUserName().checkUserEmail().checkUserPwd();
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1727/viewspace-2799344/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- js 一種物件導向的寫法 很實用 var demo=()()JS物件
- Java常見知識點彙總(③)——物件導向基礎Java物件
- [寫作中...]Js物件導向(2): 建立物件JS物件
- Javascript物件導向與繼承JavaScript物件繼承
- js建立物件的各種方法以及優缺點JS物件
- JavaScript 物件導向JavaScript物件
- JS物件導向JS物件
- 更多物件導向的JavaScript物件JavaScript
- JavaScript 的物件導向(OO)JavaScript物件
- 七種常見的物件導向設計原則物件
- 常見的三種代理IP協議的優缺點協議
- 常見物聯網模型優缺點簡介模型
- JavaScript物件導向—物件的建立和操作JavaScript物件
- Js物件導向(1): 理解物件JS物件
- 物件導向與程式導向物件
- 程式導向與物件導向物件
- JavaScript7:物件導向JavaScript物件
- 【讀】JavaScript之物件導向JavaScript物件
- JavaScript 物件導向初步理解JavaScript物件
- [javascript高手之路]寄生組合式繼承的優勢JavaScript繼承
- php中的程式導向與物件導向PHP物件
- js 物件導向總結JS物件
- 淺談JS物件導向JS物件
- JS物件導向設計-建立物件JS物件
- javascript:物件導向的程式設計JavaScript物件程式設計
- js物件導向設計---建立物件的方式JS物件
- 物聯網常見的十種定位技術的優缺點
- JS 中的物件導向 prototype classJS物件
- JS物件導向的程式設計JS物件程式設計
- 「Golang成長之路」物件導向篇Golang物件
- 《JavaScript物件導向精要》之六:物件模式JavaScript物件模式
- 《JavaScript物件導向精要》之三:理解物件JavaScript物件
- 舉例說明物件導向程式設計有什麼缺點?物件程式設計
- 1.16 JavaScript7:物件導向JavaScript物件
- 《JavaScript物件導向精要》系列文章JavaScript物件
- JavaScript 物件導向實戰思想JavaScript物件
- JavaScript物件導向詳解(原理)JavaScript物件
- JS物件導向程式設計(一):物件JS物件程式設計