希望能自己獨立的寫出這個小冊。在博客園的第一篇博文,還是寫關於技術方面的,但願語言組織好點。 自己也不算是初級小白了,畢竟學習前端知識很長一段時間了。兩個月前也嘗試寫過一些封裝,但對封裝質量並不滿意,後來讀了一本書,叫《JavaScript設計模式與開發實踐》,從中受益很多。作者是我們國內的騰訊前端 ...
希望能自己獨立的寫出這個小冊。在博客園的第一篇博文,還是寫關於技術方面的,但願語言組織好點。
自己也不算是初級小白了,畢竟學習前端知識很長一段時間了。兩個月前也嘗試寫過一些封裝,但對封裝質量並不滿意,後來讀了一本書,叫《JavaScript設計模式與開發實踐》,從中受益很多。作者是我們國內的騰訊前端工程師,他用通俗易懂的語言組織方式讓我明白了很多開發技巧。
封裝一個方法或者插件是很有必要的。在實際工作開發中,對於出現頻率很高的技術,完全可以把核心技術封裝起來,這樣做是很節約時間成本的,因為以後再碰到就不用在花費時間再寫一遍。當然,如何很好的來封裝是很有考驗性的。封裝一個東西,我們要考慮到很多方面。比如邊界條件是否滿足、代碼可復用如何、再高點,對於性能的要求等等。
我認為,封裝好一個插件,不僅要多方面考慮,更重要的是其封裝思想(當然自己封裝能力很一般)。大部分設計模式的主題是將不變的部分和變化的部分分隔開。我們把不變的部分封裝起來,把可變的部分儘量更好的組織,這是很有必要的。
比如,寫一個驗證昵稱的功能,當輸入完畢,點擊提交,然後驗證輸入的昵稱是否合法,這個小功能完全可以寫成插件的形式。
按照那句話:將不變的部分和變化的部分分隔開。我們把不變的部分封裝起來。
開始找認為可變和不可變的部分,我覺得可變的是合法或不合法的字元,而不可變的是驗證的這一過程(無非是一個正則匹配過程),最重要的是對哪個元素進行驗證,當然還要獲取到提交按鈕。於是進行分離。
最原始的做法是把可變的用函數參數代替:
1 let testRegular = (reg,btnElem,txtElem) => { 2 btnElem.addEventListener('click',() => { 3 let val = txtElem.value; 4 if (val.match(reg)) { 5 alert('輸入昵稱非法!'); 6 } else { 7 alert('輸入通過!'); 8 } 9 },false); 10 }
但是這樣是遠遠不夠的,因為函數參數多的話我們不好進行管理。不如把參數改為對象的形式傳入。這樣使代碼更加美觀,把可變的都放在一個對象里,更好管理。
1 let testRegular = (obj) => { 2 obj.submitBtn.addEventListener('click',() => { 3 let val = obj.txtElem.value; 4 if (val.match(obj.testReg)) { 5 alert('輸入昵稱非法!'); 6 } else { 7 alert('輸入通過!'); 8 } 9 },false); 10 }
但是,我們並不滿足於此。我想把驗證昵稱的功能擴展到可以驗證表單中的輸入框,比如事件類型,我不但可以點擊提交,還可以敲擊鍵盤enter提交,失去焦點時就會驗證等等,於是進行改進:
1 let obj = { 2 txtElem: document.querySelector('#nickName'), 3 submitBtn: document.querySelector('#submit'), 4 testReg: /\s/g 5 }; // obj 對象是可變的部分 6 7 let testRegular = (obj) => { // 不變的部分 8 9 return function(){ 10 let val = obj.txtElem.value; // 不好的是,如果是點擊事件,只能驗證一個輸入框。 11 if (val.match(obj.testReg) || val == '') { 12 alert('輸入昵稱非法!'); // 可把其中的操作(也是可變的)寫入一個函數中,調用即可 13 } else { 14 alert('輸入通過!'); 15 } 16 } 17 } 18 obj.oEven = testRegular(obj); 19 // 可變的事件操作 20 obj.submitBtn.addEventListener('click',obj.oEven); 21 obj.txtElem.addEventListener('keydown',function(e){ 22 if(e.keyCode === 13){ 23 obj.oEven(); 24 } 25 }); 26 obj.txtElem.addEventListener('blur',obj.oEven);
當然在真正的開發中,肯定沒那麼簡單,特別是驗證後的操作,不可能只是彈個窗的效果,所以,條件語句內的代碼也是可變的部分。這時候可以把條件語句里的代碼,寫在一個個的函數里,判斷後,調用即可。
寫完後,發現這個例子並不恰當。。。初衷是驗證驗證昵稱是否合法。如果要對錶單進行驗證,會更複雜。畢竟是第一篇博文,以後會更加嚴謹,,,
封裝不單指封裝插件,還可以擴展對象方法。比如:寫一個自己的pop數組方法,傳入參數(索引),就能刪除該數組索引處的值:
1 Array.prototype.myPop = function(num){ 2 let ary = []; 3 this.forEach((item,index) => { 4 if(num !== index){ 5 ary.push(item); 6 } 7 8 }); 9 return ary; 10 }
完善邊界條件:如:輸入負值時刪除的是倒數的索引值;超出索引時報錯;非數字類型參數也報錯
1 Array.prototype.myPop = function(num){ 2 let ary = []; 3 let len = this.length; 4 if(typeof(num) !== 'number' && (num < -len || num >= len)){ 5 console.error("須輸入數字,且大小不得超過數組長度!"); 6 } 7 if(num < 0 && num >= -len){ 8 num = num + len; 9 } 10 this.forEach((item,index) => { 11 if(num !== index){ 12 ary.push(item); 13 } 14 }); 15 return ary; 16 }
當然,可以把開方法擴展到字元串:只需把字元串先變成數組(split方法),對數組操作,在拼接起來就行了(join)。
1 String.prototype.myPop = function(num){ 2 let strArr = this.split(''), 3 newArr = [], 4 len = strArr.length; 5 if(typeof(num) !== 'number' && (num < -len || num >= len)){ 6 console.error("須輸入數字,且大小不得超過數組長度!"); 7 } 8 if(num < 0 && num >= -len){ 9 num = num + len; 10 } 11 strArr.forEach((item,index) => { 12 if(num !== index){ 13 newArr.push(item); 14 } 15 }); 16 let str = newArr.join(''); 17 return str; 18 }
對應的 ---> myPush() 方法:在指定索引後插入指定的值:索引是正時在索引前插入,索引是負時,在索引之後插入。以數組為例:
1 Array.prototype.myPush = function(n,val,position = 'after'){ // 在索引位置之後插入指定的數字 num 2 let arr = [], 3 len = this.length; 4 5 if (typeof (n) !== 'number' && (n < -len || n >= len)) { 6 console.error("須輸入數字,且大小不得超過數組長度!"); 7 } 8 if (n < 0 && n >= -len) { 9 n = n + len; 10 } 11 if(position === 'after'){ 12 this.forEach((item, index) => { 13 arr.push(item); 14 if (n === index) { 15 arr.push(val); 16 } 17 }); 18 }else if(position === 'before'){ 19 this.forEach((item, index) => { 20 if (n === index) { 21 arr.push(val); 22 } 23 arr.push(item); 24 }); 25 } 26 return arr; 27 }
對Math對象的擴展:比如對普通的一元多項式的積分;(Math對象沒有prototype)
1 Math.integral = function(ratioAry,rangeAry = null){ 2 let result = 0; 3 let isAry = Object.prototype.toString; 4 5 if(isAry.call(ratioAry) != '[object Array]' && (rangeAry != null || isAry.call(rangeAry) != '[object Array]')){ 6 console.error("須輸入數組形式的參數!"); 7 } 8 9 ratioAry.forEach(item => { 10 item[1] = item[1] + 1; 11 item[0] = item[0] / item[1]; 12 }); 13 if(!rangeAry){ 14 return ratioAry; 15 }else{ 16 let upper = rangeAry[0], 17 lower = rangeAry[1]; 18 19 ratioAry.forEach(item => { 20 result += item[0] * (Math.pow(upper,item[1])) - item[0] * (Math.pow(lower, item[1])); 21 }); 22 return result; 23 } 24 25 }
調用時,第一個參數需輸入二維數組 [[1,1],[2,-2],....] 每一個長度為2的子數組表示一個項,第一位表示繫數,第二位表示指數。而函數的第二個參數也是一個數組(如 [2,6] 是個一維長度為2的數組),有值時是一個定積分,會返回結果。
對於對象的方法的擴展還有很多。可以寫成個文件,保存起來。初入博客園,先寫那麼多。自己水平有限,入博客園的目的就是為了提高自己的代碼編寫質量和寫作能力,日後還要多加努力!