javascript
是一門弱語言,他有著分同一般的靈活性使它迅速的成為幾乎人人必會的一門語言,but,你們使用的姿勢真的正確嗎?
在以前的開發過程當中,老闆:給我加個驗證使用者郵箱
、驗證使用者簡訊...
功能!
function checkMessage(){...}
function checkEmail(){...}
function ... //茫茫多的函式
複製程式碼
這樣寫好了之後 function
是全域性的變數,那麼是全域性的就難免會對專案javascript環境造成汙染,可能會對其他同事造成影響,我們首先要考慮會不會影響別人,如果別人重名對你的checkMessage
覆蓋,那麼這樣的BUG是很難發現的。為了不造成太多的全域性汙染
,我們可以這樣寫:
var checkObject = {
checkMessage:function(){},
checkEmail:function(){},
...
}
複製程式碼
首先說明,並不是這樣寫就不會造成汙染了,checkObject
依舊是全域性變數,那麼好處在哪裡呢?想一下如果Jquery的$
被覆蓋了,那麼我們頁面的
$.each | $.extends | $(#id) | $...
複製程式碼
都失效了,那麼我們很容易定位問題: Jquery
出問題了!checkObject
也是一樣,當checkObject出問題了,我們很容易定位錯誤。
呼叫:checkObject.checkMessage()
即可
那麼問題又來了:如果有同事用我的checkObject搞一些事情呢?它可以直接用我的方法麼?當然可以,問題是,你買了一本書你願意別人亂寫亂畫麼?我們可以改造一下:
var checkObject = function(){
return {
checkMessage:function(){},
checkEmail:function(){},
...
}
}
複製程式碼
我們把方法通過function
的呼叫返回,這樣別人可以這樣用 :
var check = checkObject();
check.checkEmail();
複製程式碼
我們可以再完善一下,把checkObject
看成java的類,checkMessage
,checkEmail
看成java的public
公有方法,既然看成類了,我們可以把checkObject
寫成大寫CheckObject
var CheckObject = function(){
this.checkMessage = function(){},
this.checkEmail = function(){},
...
}
複製程式碼
別人呼叫:
var check = new CheckObject(); //既然是一個類了,就要 new 來例項化了
check.checkEmail();
複製程式碼
每一次通過new
建立新物件的時候,新建立的物件都會對類this
上的屬性進行復制,你定義了兩個那麼就複製兩次,那麼再更多呢?是不是感覺有些奢侈呢,考慮我們可以運用javascript的原型prototype
來建立它:
var CheckObject = function(){
}
CheckObject.prototype.checkMessage = function(){},
CheckObject.prototype.checkEmail = function(){},
...
複製程式碼
你嫌麻煩?
var CheckObject = function(){
}
CheckObject.prototype{
checkMessage : function(){},
checkEmail : function(){},
...
}
複製程式碼
這樣我們的方法都複製到CheckObject
的原型連上去了,建立出來的物件都是通過prototype
依次尋找,都繫結在CheckObject
的原型上__proto__
Jquery
的原型鏈,是不是很熟悉的方法呢?
同志們是否好奇Jquery
的方法是如何鏈式呼叫的呢?很簡單,我來模擬一下
var CheckObject = function(){
}
CheckObject.prototype = {
checkMessage : function(){ ... return this },
checkEmail : function(){ ... return this },
...
var check = new CheckObject();
check.checkMessage().checkEmail();
複製程式碼
就這麼簡單,我們只需要將this
指代的當前物件全部返回即可。
咳咳,言歸正傳,回到物件導向程式設計的課題上
java中有 private
宣告的私有變數、 有通過public
的getter
setter
方法進行通訊,有static
修飾的靜態變數
,靜態方法
,有構造器
,那麼javascript可以使用這樣的設計模式麼?可以,跟我往下看:
我們去商店買菸
var Smoke = function(id,name){
//私有屬性
var num = 0;
//物件的公有屬性 (需要new)
this.id = id;
//私有方法
function checkID(){ return true};
//公有 setter getter 建構函式
this.setName = function(name){
this.name = name;
}
this.getName = function(){
return this.name;
}
//物件的公有屬性 (需要new)
this.information = function(){
//只有在Smoke內部才能呼叫checkID()
if(checkID()) return this.name+'香菸'+'訂單號 :'+this.id
}
}
Smoke.prototype = {
money:'10元', //公有屬性(不需要new) 直接Smoke.money[想沒想到Array的length?]
other:function(){}
}
var smoke = new Smoke(994857,'煊赫門');
smoke.information(); //"undefined香菸訂單號 :994857" ps:因為我們沒對Smoke的name屬性賦值
smoke.setName('煊赫門'); //我們賦值
smoke.information(); //"煊赫門香菸訂單號 :994857"
smoke.num; //undefined ps:很明顯他是私有屬性
smoke.checkID();//error is not function ps:很明顯私有方法
複製程式碼
如果我們沒有new
var smoke = Smoke(994857,'煊赫門');
smoke.information(); //Uncaught TypeError: Cannot read property 'information' of undefined
複製程式碼
納尼報錯了?
smoke.money; //undefind
smoke //undefind
複製程式碼
(好像明白了什麼......) 別急,讓我們看下window
window.information(); // "undefined香菸訂單號 :994857"
複製程式碼
恍然大悟,因為new是可以對當前物件(Smoke)的this
不停地賦值【上面講過】,而上面的沒有new
相當於全域性執行了Smoke()
所以是他的this
指向到 window
去了!
怎麼避免這種無操作呢?我們在Smoke內部進行型別檢查:
var Smoke = function(id,name){
var num = 0;
function checkID(){ return true};
//判斷this在執行過程中是不是屬於Smoke,如果是說明是new過的 0.0
if(this instanceof Smoke){
this.id = id;
this.setName = function(name){
this.name = name;
}
this.getName = function(){
return this.name;
}
//物件的公有屬性 (需要new)
this.information = function(){
//只有在Smoke內部才能呼叫checkID()
if(checkID()) return this.name+'香菸'+'訂單號 :'+this.id
}
}else{
return new Smoke(id,name);//內部重新new一個 0.0
}
}
複製程式碼
看完了麼,感覺爽不,是不是感覺就是在寫java呢,其實javascript就是靈活在這裡,這只是javascript一種常用的物件導向設計模式,後面我會將更多的設計模式,這些設計模式都是經過前人無數心血總結出來給我們的,我們為什麼不用呢?
感謝[他居然愛吃蟲]
同學對本文的校對
如果您覺得還算不錯可以關注我持續看我的文章,大概方向:前後端語言設計模式
、如何設計好一款框架
、原始碼導讀
、技術實踐
。
- 青年才俊可以入群交流:
147255248