1. 程式人生 > >javascript進階之路1

javascript進階之路1

kobject 回顧 只有一個 變量 創建方式 驗證 spa 你知道 問題

路漫漫其修遠兮,吾將禿了頭依然不見大明湖畔的夏雨荷。

當年我還是個javascript小白,項目經理分下來一個驗證表單功能的任務,內容不多,僅需要驗證用戶名、郵箱、密碼等。

我一看so easy,於是便寫下幾個函數。

 1 function checkName () {
 2    //驗證姓名
 3 }
 4 
 5 function checkEmail () {
 6    //驗證郵箱
 7 }
 8 
 9 function checkPassword () {
10    //驗證密碼
11 }

正要將吾之傑作提交到團隊項目裏。

正在此時,一位頭發稀疏,腦殼發亮,滿臉胡渣的長者看著將要提交的代碼搖了搖頭說:“小白,等一下,先不要提交。”

“怎麽了?”

“你創建了很多全局變量呀。”

“全局變量?我只是寫了幾個函數而已。”

“函數不是變量麽?”長者反問道。

此時小白不知所措,心想:“難道函數是變量?”臉瞬間黑了下來。

長者見狀忙笑著說:“別著急,你看,如果我這麽聲明幾個變量來實現你的功能你看可以麽?”

 1 var checkName = function () {
 2    //驗證姓名
 3 }
 4 
 5 var checkEmail = function () {
 6    //驗證郵箱
 7 }
 8 
 9 var checkPassword = function () {
10    //驗證密碼
11 }

“一樣的,只不過。。。。。。”

“對,只不過這個在用的時候要提前聲明,但是這麽看你就會發現你創建了3個函數保存在變量裏來實現你的功能,而你寫的是將你的變量名放在function後面而已,它也代表了你的變量。所以說你也聲明了3個全局變量。”

“這有什麽問題呢?”

“從功能上講當然沒問題,但是今天你加入了我們的團隊,在團隊開發中你所寫的代碼就不能只考慮自己了,也要考慮不影響到他人,如果別人也定義了同樣的方法就會覆蓋掉原有的功能了。如果你定義了很多方法,這種相互覆蓋的問題是很不容易察覺到的。”

“那我應該如何避免呢?”

“你可以將它們放在一個變量裏保存,這樣就可以減少覆蓋或被覆蓋的風險,當然一單被覆蓋,所有的功能都會失效,這種現象也是很明顯的,你自然也會很輕易地察覺到。”

“可是我該如何做呢?”小白迫不及待滴問道。

“一猜你就會問。”

“好吧,請你先簡單滴說一下。”

“對象你知道吧,它有屬性和方法,而如果我們要訪問它的屬性或方法時,可通過點語法向下遍歷查詢得到。我們可以創建一個檢測對象,然後把我們的方法放在裏面。”

 1 var CheckObject = {
 2      checkName : function () {
 3          //驗證姓名
 4     },
 5     checkEmail : function () {
 6          //驗證郵箱
 7     },
 8     checkPassword : function () {
 9          //驗證密碼
10     },
11 }

“此時我們將所有的函數作為CheckObject對象的方法,這樣我們只有一個對象,而我們要想使用它們也很簡單,比如檢測姓名CheckObject.checkName(),只是在我們原來使用的函數式前面多了一個對象名稱。”

“哦,這樣啊,但是我們既然可以通過點語法來使用方法,我們是不是也可以這麽創建呢?”

“當然,不過首先你要聲明一個對象,然後給它添加方法,當然在javascript中函數也是對象,所以你可以這麽做:”

 1 var CheckObject = function () {};
 2 CheckObject.checkName = function () {
 3     //驗證姓名
 4 }
 5 CheckObject.checkEmail = function () {
 6    //驗證郵箱
 7 }
 8 CheckObject.checkPassword = function () {
 9     //驗證密碼
10 }

“使用和前面一樣,比如CheckObject.checkName(),”長者接著說,“現在雖然能滿足你的需求,但當別人想用你的寫的對象方法時就有些麻煩了,因為這個對象不能復制一份,或者說這個對象類在用new關鍵字創建新的對象時,新創建的對象是不能繼承這些方法的。”

“但是復制又有什麽用呢?”小白不解地問道。

“給你舉個例子吧,假如你有一百塊,你的小夥伴看見了也想要一百塊,可只有一百塊怎麽辦?但如果你有一臺印鈔機,那麽好吧,誰想要就給他印一百。”

“哦,有些明白了,但是我該如何做呢?”

長者解釋道:“如果你想簡單地復制一下,你可以將這些方法放在一個函數對象中。”於是長者將代碼寫下。

 1 var CheckObject = function () {
 2     return {
 3         checkName : function () {
 4             //驗證姓名
 5         },
 6         checkEmail : function () {
 7             //驗證郵箱
 8         },
 9         checkPassword : function () {
10            //驗證密碼
11         } 
12     }
13 }

小白看了看代碼,思考一下說:“哦,你寫的看上去是,當每次調用這個函數的時候,把我們之前寫的那個對象返回出來,當別人每次調用這個函數時都返回了一個新對象,這樣執行過程中明面上是CheckObject對象,可實際上是返回的新對象。這樣每個人在使用時就互不影響了。比如想檢測郵箱可以像這樣吧。”

1 var a = CheckObject (); 2 a.checkEmail ();

“嗯,對”長者接著說,“雖然通過創建了新對象完成了我們的需求,但是他不是一個真正意義上類的創建方式,並且創建的對象a和對象CheckObject沒有任何關系(返回出來的對象本身就與CheckObject對象無關),所以我們還要對其稍加改造一下。”

 1 var CheckObject = function () {
 2     this.checkName = function () {
 3       //驗證姓名
 4    }
 5    this.checkEmail = function () {
 6      //驗證郵箱
 7    }
 8    this.checkPassword = function () {
 9     //驗證密碼
10   }
11 }

“像上面這樣的對象就可以看成類了。”長者繼續說。

“那麽我們使用它還想之前那樣創建對象的方法創建麽?”小白追問道。

“不,既然是一個類,你就要用關鍵字new來創建了。”

1 var a = new CheckObject();
2 a.checkEmail();

“這樣你就可以用CheckObject類創建出來的對象了。”

“如果我和我的小夥伴們都對類實例化了(用類創建對象),那麽我們每個人都會有一套屬於自己的方法吧。”小白不解地問道。

“當然,你看,我們是把所有的方法放在函數內部了,通過this定義的,所以每一次通過new關鍵字創建新對象的時候,新創建的對象都會對類的this上的屬性進行復制。所以這些新創建的對象都會有一套自己的方法,然而有時候這麽做造成的消耗是很奢侈的,我們需要處理一下。”

 1 var CheckObject = function ()  {
 2     
 3 };
 4 CheckObject.prototype.checkName = function () {
 5     //驗證姓名
 6 }
 7 CheckObject.prototype.checkEmail = function () {
 8     //驗證郵箱
 9 }
10 CheckObject.prototype.checkPassword = function () {
11     //驗證密碼
12 }

“但有一點你要記住,這兩種方法不能混著用,否則一旦混用,如在後面為對象的原型對象賦值新對象時,那麽它將會覆蓋掉之前對prototype對象賦值的方法。”長者補充說。

“知道了,不過我們要使用這種方式定義的類是不是要像下面這樣呢?”小白問道。

1 var a = new CheckObject(); 2 a.checkName(); 3 a.checkEmail(); 4 a.checkPassword();

“沒錯,但是你發現沒,你調用了3個方法,但是你對對象a書寫了3遍。這是可以避免的,那就要在你聲明的每一個方法末尾處將當前對象返回,在javascript中this指向的就是當前對象,所以你可以將它返回。例如我們開始寫的第一個對象還記得麽?改動它很簡單,像下面這樣就可以。”

 1 var CheckObject = {
 2    checkName : function () {
 3       //驗證姓名
 4       return this;
 5    },
 6    checkEmail : function () {
 7       //驗證郵箱
 8       return this;
 9    },
10    checkPassword : function () {
11       //驗證密碼
12       return this;
13    },
14 }

“此時我們要想使用它就可以這樣:”

1 CheckObject.checkName().checkEmail().checkPassword();

“當然同樣的方式還可以放到類的原型對象中。”

 1 var CheckObject = function () {};
 2 CheckObject.prototype = {
 3    checkName : function () {
 4       //驗證姓名
 5       return this;
 6    },
 7    checkEmail : function () {
 8       //驗證郵箱
 9       return this;
10    },
11    checkPassword : function () {
12       //驗證密碼
13       return this;
14    }
15 }

“但使用時候也要先創建一下:”

1 var a = new CheckObject(); 2 a.checkName().checkEmail().checkPassword();
小白回顧著這些從未見過的代碼方式內心很激動,長者見小白對JavaScript如此著迷,於是補充了兩句。

“如果你看過prototype.js的代碼,我想你會想到下面的書寫方式。”

“prototype.js是什麽?”小白問道。

“一款javascript框架,裏面為我們方便地封裝了很多方法,它最大的特點就是對原生對象(JavaScript語言為我們提供的對象類,如Function、Array、Object等)的拓展,比如你想給每一個函數都添加一個檢測郵箱的方法就可以這麽做。”

1 Fucntion.prototype.checkEmail = function () {
2    //驗證郵箱
3 }

“這樣你在使用這個方法的時候就比較方便了,如果你習慣函數形式,那麽你可以這麽做。”

1 var f = new Function(); 2 f.checkEmail();

“但是你這麽做在我們這裏是不允許的,因為你汙染了原生對象Function,所以別人創建的函數也會被你創建的函數所汙染,造成不必要的開銷,但你可以抽象出一個統一添加方法的功能方法。”

1 Function.prototype.addMethod = function (name, fn) {
2   this[name] = fn;
3 }

“這樣如果你想添加郵箱驗證和姓名驗證方法你可以這樣做。”

1 var methods = function () {};

或者

1 var methods = new Function();
2 methods.addMethod(‘checkName‘, function () {
3   //驗證姓名
4 });
5 methods.addMethod(‘checkEmail‘, function () {
6    //驗證郵箱
7 });
8 methods.checkName();
9 methods.checkEmail();

“呀,這種方式很奇特呀。不過我想鏈式添加方法,是不是在addMethod中將this返回就可以呀,這麽做可以麽?”

1 Function.prototype.addMethod = function (name, fn) {
2   this[name] = fun;
3   return this;
4 }

“當然,所以你再想添加方法就可以這樣了:”

1 var methods = function () {};
2 methods.addMethod(‘checkName‘, function () {
3    //驗證姓名
4 }).addMethod(‘checkEmail‘, function () {
5    //驗證郵箱
6 });

“那麽小白,我問你,我如果想鏈式使用你知道該如何做麽?”

小白想了想說,既然添加方法的時候可以將this返回實現,那麽添加的每個方法將this返回是不是就可以實現呢?”

於是小白這麽寫下:

 1 var methods = function () {
 2 };
 3 methods.addMethod(‘checkName‘, function () {
 4   //驗證姓名
 5    return this;
 6 }).addMethod(‘checkEmail‘, function () {
 7   //驗證郵箱
 8    return this;
 9 });
10 
11 methods.checkName().checkEmail();

“真的可以呀!”小白興奮滴說。

“可是在你測試的時候,你用的是函數式調用方式?對於習慣於類式調用方式的同學來說,他們可以這樣簡單更改一下。”

1 Function.prototype.addMethod = function (name, fn) {
2   this.prototype[name] = fn;
3   return this;
4 }

“此時我們還按照上一種方式添加方法。”

1 var Methods = function() {};
2 Methods.addMethod(‘checkName‘, function () {
3    //驗證姓名
4 }).addMethod(‘checkEmail‘, function () {
5   //驗證郵箱
6 });

“但是我們在使用時就要註意了,不能直接使用,要通過new關鍵字來創建新對象了。”

1 var m = new Methods();
2 m.checkEmail();

小白興奮滴看著這一行行代碼情不自禁地叫了一聲“這真是一種藝術”。

javascript進階之路1