我對封裝的理解

来源:https://www.cnblogs.com/MH-wang-blog/archive/2018/12/02/10053053.html
-Advertisement-
Play Games

希望能自己獨立的寫出這個小冊。在博客園的第一篇博文,還是寫關於技術方面的,但願語言組織好點。 自己也不算是初級小白了,畢竟學習前端知識很長一段時間了。兩個月前也嘗試寫過一些封裝,但對封裝質量並不滿意,後來讀了一本書,叫《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的數組),有值時是一個定積分,會返回結果。 

 

對於對象的方法的擴展還有很多。可以寫成個文件,保存起來。初入博客園,先寫那麼多。自己水平有限,入博客園的目的就是為了提高自己的代碼編寫質量和寫作能力,日後還要多加努力!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • frameset 定義 W3C是這樣定義frameset框架的,通過使用框架,你可以在同一個瀏覽器視窗中顯示不止一個頁面。每份HTML文檔稱為一個框架,並且每個框架都獨立於其他的框架。註意,這是HTML框架,不是前端框架,與node.js,vue.js等不同。 垂直切割 屬性為cols。例如: <f ...
  • 先說幾個概念: 1、js代碼從上往下執行 2、變數提升: 變數提升是瀏覽器的一個功能,在運行js代碼之前,瀏覽器會給js一個全局作用域叫window,window分兩個模塊,一個叫記憶體模塊,一個叫運行模塊,記憶體模塊找到當前作用域下的所有帶var和function的關鍵字,執行模塊執行js代碼,從上到 ...
  • 聲明 本系列文章內容全部梳理自以下幾個來源: 《JavaScript權威指南》 "MDN web docs" "Github:smyhvae/web" "Github:goddyZhao/Translation/JavaScript" 作為一個前端小白,入門跟著這幾個來源學習,感謝作者的分享,在其基 ...
  • 什麼是作用域:瀏覽器給js的生存環境叫作用域。 什麼是變數提升: Js代碼執行前,瀏覽器會給一個全局作用域window Window分兩個模塊一個是存儲模塊一個是執行模塊 存儲模塊找到所有的var和function 關鍵字給這些變數添加記憶體地址 執行模塊,代碼從上到下執行,遇到變數就會去存儲模塊查找 ...
  • 1.事件 瀏覽器客戶端上客戶觸發的行為都稱為事件 所有的事件都是天生自帶的,不需要我們去綁定,只需要我們去觸發。 通過 obj.事件名=function(){} 事件名:onmouseover 滑鼠懸浮 onmouseout 滑鼠移除 onmousedown滑鼠按下 onmouseup 滑鼠抬起 o ...
  • 元素的屬性 div.attributes 是所有標簽屬性構成的數據集合 div.classList 是所有class名構成的數組集合 在classList的原型鏈上看以看到add()和remove() 1.client系列 (1) clientWidth/clientHeight 是我們設置的寬和高 ...
  • @[toc] .val()實例方法的三種用法 1. $('xxx').val() : 獲取匹配的元素集合中第一個元素的當前value屬性值(property) 2. $('xxx').val(value) : 設置匹配的元素集合中每個元素的value屬性值(property) 3. $('xxx') ...
  • 在列表展示中,經常會使用卡片的內容展示形式,為了美觀,常常要求各卡片間的間隙是一致的。 卡片內容不一樣可能高度不等,但一般來說為了整體的一致性,會限制每個卡片的寬高都相等。 本文就基於寬高一致的多個卡片,在不同屏幕大小下,每行卡片數量可能有調整,考量如何實現等間隙的佈局。 點我預覽 放置一張張卡片項 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...