使用AOP改善javascript代碼
Aop又叫面向切面編程,用過spring的同學(xué)肯定對它非常熟悉,而在js中,AOP是一個被嚴重忽視的技術(shù)點,這篇就通過下面這幾個小例子,來說說AOP在js中的妙用.
1, 防止window.onload被二次覆蓋.
2,無侵入的統(tǒng)計代碼.
3, 分離表單請求和校驗.
4,給ajax請求動態(tài)添加參數(shù).
5,職責(zé)鏈模式.
6, 組合代替繼承.
先給出before和after這2個“切面”函數(shù). 顧名思義,就是讓一個函數(shù)在另一個函數(shù)之前或者之后執(zhí)行,巧妙的是,before或者after都可以和當前的函數(shù)公用this和arguments, 這樣一來供我們發(fā)揮的地方就多著了.
處理window.onload被二次覆蓋.
前段時間看到QQ群里有個人問問題,要改寫window.onload, 怎么才能不把以前的window.onload函數(shù)覆蓋掉.
最原始的方案肯定是直接在原來的window.onload里添上你的新代碼.
這樣的壞處非常明顯,需要去改動原有的函數(shù), 是侵入性最強的一種做法.
另外一種稍微好點的方案是用中間變量保存以前的window.onload;
這樣一來,多了一個討厭的中間變量__onload, 來管理它也要花費一些額外的成本.
試想一下這個場景,當人覺得天氣冷,出門的時候很自然選擇穿上一件貂皮大衣,而不是把自己的皮扯掉換成貂皮. 動態(tài)裝飾的好處就體現(xiàn)出來了,完全不會侵入之前的函數(shù).
無侵入的統(tǒng)計代碼
本身跟邏輯沒有任何關(guān)聯(lián)的統(tǒng)計代碼要被硬插進函數(shù)里, 這點相信很多搞過上報的同學(xué)都很不爽. 比如下面這段代碼, 用來統(tǒng)計一個創(chuàng)建1000個節(jié)點的函數(shù)在用戶的電腦上要花費多少時間.
用aop的方式,不再需要在函數(shù)內(nèi)部做改動,先定義一個通用的包裝器.
只要一行代碼,便能給任何函數(shù)都加上統(tǒng)計時間的功能.
分離表單請求和校驗
我們在提交表單之前經(jīng)常會做一些校驗工作,來確定表單是不是應(yīng)該正常提交. 最糟糕的寫法是把驗證的邏輯都放在send函數(shù)里面.
而更好的方式是把所有的校驗規(guī)則用策略模式放到一個集合里,返回false或者true來決定是否通過驗證. 這樣可以隨意的選擇和更換校驗規(guī)則.
這樣還有一個缺點,校驗和發(fā)送請求這2個請求耦合到了一個函數(shù)里面, 我們用aop來把它們分離開來, 把validata做成插件化,真正的即插即用. 只需把send函數(shù)改成:
過最前面Function.prototype.before的代碼不難看出,我們約定,當前一個函數(shù)返回false, 就會阻斷下一個函數(shù)的執(zhí)行, 所以當validata返回false的時候, 便不再繼續(xù)執(zhí)行send. 而因為之前提到的before函數(shù)可以和當前函數(shù)公用this和arguments, 所以value參數(shù)也能順利的傳遞到validata函數(shù)里.
給ajax請求動態(tài)添加參數(shù)
第一個例子里window.onload是用的after后置裝飾, 這里是用before前置裝飾. 在ajax請求之前動態(tài)添加一些參數(shù).
我們遇到過很多跨域的請求, jsonp和iframe都是很常用的方式. 之前在我們的項目里,用參數(shù)retype=jsonp表示是jsonp請求, retype=iframe表示是iframe請求. 除此之外這2個請求的參數(shù)沒有任何區(qū)別. 那么可以用before把retype參數(shù)動態(tài)裝飾進去.
先定義一個ajax請求的代理函數(shù).
這個函數(shù)里面沒有邏輯處理和分支語句,它也不關(guān)心自己是jsonp請求還是iframe請求. 它只負責(zé)發(fā)送數(shù)據(jù), 是一個單一職責(zé)的好函數(shù).
接下來在發(fā)送請求前放置一個before裝飾器.
開始發(fā)送請求:
職責(zé)鏈模式.
職責(zé)鏈模式在js中典型的應(yīng)用場景是事件冒泡. 將所有子節(jié)點和父節(jié)點連成一條鏈,并沿著這條鏈傳遞事件,直到有一個節(jié)點能夠處理它為止. 職責(zé)鏈模式是消除過多的if else語句的神器.
拿最近做的一個需求來舉例, 有個文件上傳的功能, 提供了控件,html5, flash, 表單上傳這4種上傳方式. 根據(jù)它們的優(yōu)先級以及瀏覽器支持情況來判斷當前選擇哪種上傳方式. 在我進行改造之前,它的偽代碼大概是這樣:
當然實際的代碼遠不只這么多,其中還包括了各種控件初始化,容錯等情況。有天我需要屏蔽掉flash,看起來是很簡單的需求,但難度實際跟在心臟旁邊拆掉一根毛線血管類似.
如果試試職責(zé)鏈模式呢, 看看事情將變得多簡單:
第一步先改寫之前的after函數(shù),使得返回一個對象時阻斷職責(zé)鏈的傳遞,而返回null時繼續(xù)傳遞請求。
接下來把每種控件的創(chuàng)建方式都包裹在各自的函數(shù)中, 確保沒有邏輯交叉和相互污染.
最后用職責(zé)鏈把它們串起來:
可以預(yù)見,某天我又需要屏蔽掉flash, 那時的我只需要改動這一行代碼. 改成:
組合代替繼承
很多時候我們在設(shè)計程序的時候,會遇到使用組合還是繼承的問題. 通常來講, 使用組合更靈活輕巧. 還是拿之前文件上傳來舉例.
我定義了一個超類Upload, 衍生出4個子類.
Plugin_Upload, Html5_Upload, Flash_Upload以及Form_Upload.
Plugin_Upload會繼承父類,得到Upload的大部分功能, 然后對控件上傳的一些特性進行個性定制. 比如其它3種上傳方式都是選擇文件后便開始上傳. 而控件上傳在開始上傳之前會經(jīng)過一輪文件掃描.
第一種做法是Plugin_Upload繼承Upload, 然后重寫它的start_upload方法.
用更輕的組合方式, 可以直接給原來的start_upload函數(shù)裝飾上掃描功能, 甚至不需要衍生一個額外的子類.
- Springboot 使用 JSR 303 對 Controller 控制層校驗及 Service 服務(wù)層 AOP 校驗 使用消息資源文件對消息國際化
- javascript AOP 實現(xiàn)ajax回調(diào)函數(shù)使用比較方便
- 初識SmartJS - AOP三劍客
- JavaScript實現(xiàn)AOP詳解(面向切面編程,裝飾者模式)
- Javascript aop(面向切面編程)之a(chǎn)round(環(huán)繞)分析
- JavaScript之AOP編程實例
- JavaScript AOP編程實例
- JavaScript中AOP的實現(xiàn)與應(yīng)用
- 關(guān)于AOP在JS中的實現(xiàn)與應(yīng)用詳解
相關(guān)文章
淺析JavaScript中的call、apply和bind方法
JavaScript中的call、apply和bind方法是用于改變函數(shù)執(zhí)行上下文和預(yù)先設(shè)置參數(shù)的強大工具,它們在編寫可維護和優(yōu)雅的代碼時起到了重要的作用,本文將介紹這些方法的原理和使用場景,并展示如何將它們應(yīng)用于你的代碼中,使其更加漂亮2023-06-06詳解JavaScript什么情況下不建議使用箭頭函數(shù)
箭頭函數(shù)作為ES6新增的語法,在使用時不僅能使得代碼更加簡潔,而且在某些場景避免this指向問題。但是箭頭函數(shù)不是萬能的,也有自己的缺點以及不適用的場景,本文總結(jié)了JavaScript什么情況下不建議使用箭頭函數(shù),感興趣的可以了解一下2022-06-06javascript中的nextSibling使用陷(da)阱(keng)
關(guān)于HTML/XML節(jié)點的問題,在IE中nextSibling不會返回文本節(jié)點,而chrome或者firefox等會返回文本節(jié)點2014-05-05layer設(shè)置maxWidth及maxHeight解決方案
這篇文章主要介紹了layer設(shè)置maxWidth及maxHeight解決方案,非常不錯,具有一定的參考借鑒價值 ,需要的朋友可以參考下2019-07-07