摘要:面向切面編程嗯,百度百科一下為的縮寫,意為面向切面編程,通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。
面向切面編程
~~~~ 嗯,百度百科一下 ~~~~
AOP 為 Aspect Oriented Programming 的縮寫,意為:面向切面編程,通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。AOP 是 OOP 的延續(xù),是軟件開(kāi)發(fā)中的一個(gè)熱點(diǎn),也是 Spring 框架中的一個(gè)重要內(nèi)容,是函數(shù)式編程的一種衍生范型。利用 AOP 可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開(kāi)發(fā)的效率。
作為前端的小萌理解為,就是將除主流程外的其他業(yè)務(wù)剝離出來(lái),然后從側(cè)面切入。對(duì)原功能無(wú)侵入式的修改。
話不多說(shuō),來(lái)個(gè)網(wǎng)上的經(jīng)典例子:
業(yè)務(wù)邏輯:
主業(yè)務(wù):修改數(shù)據(jù)庫(kù)
切入點(diǎn) 1:修改前打印日志
切入點(diǎn) 2:修改后打印日志
Function.prototype.before = function(beforeFunc) { let that = this return function() { beforeFunc.apply(this, arguments) return that.apply(this, arguments) } } Function.prototype.after = function(afterFunc) { let that = this return function() { let ret = that.apply(this, arguments) afterFunc.apply(this, arguments) return ret } } function updateDb() { console.log(`update db`) } function beforeUpdateDb() { console.log(`before update db`) } function afterUpdateDb() { console.log(`updated db`) } updateDb = updateDb.before(beforeUpdateDb).after(afterUpdateDb) updateDb()
原理:其實(shí)就是將主業(yè)務(wù)updateDb包裹2次,返回一個(gè)新的方法。新方法會(huì)在原方法調(diào)用前后調(diào)用切入方法,避免在主方法上直接改動(dòng)。
這樣的可讀性和代碼維護(hù)性是不是很差,下面用裝飾器看看如何實(shí)現(xiàn)切面編程,
裝飾器 decorator裝飾器是ES7現(xiàn)代游覽器并不兼容,需要babel轉(zhuǎn)譯,插件(babel-plugin-transform-decorators-legacy)
裝飾器只能作用于類本身、類的方法或?qū)傩浴⒃L問(wèn)操作符
修飾器“@”為標(biāo)識(shí)符
1 對(duì)類的裝飾@create class Apes { } // 修飾類本身 function create(className) { className.prototype.create = function() { console.log("制造工具") } return descriptor } let apes1 = new Apes() apes1.create() // 制造工具
對(duì)類本身修飾:create(className)。裝飾器本質(zhì)就是編譯時(shí)執(zhí)行的函數(shù)。
要修飾子類,通過(guò)要className.prototype修飾子類。
2 對(duì)類的方法修飾class Apes { @eatMore eat() { console.log("吃水果") } } // 修飾方法 function eatMore(className, propName, descriptor) { //console.log(descriptor) let value = descriptor.value descriptor.value = function() { console.log("吃土") value() } return descriptor } let apes1 = new Apes() apes1.eat()
對(duì)類的方法裝飾 eatMore(className, propName, descriptor)
className - 被修飾的類 propName - 被修飾的屬性名 descriptor - 該屬性的描述對(duì)象
通過(guò)descriptor屬性描述符看出 依賴于ES5的Object.defineProperty
復(fù)習(xí)一下Object.defineProperty
value:屬性的值,默認(rèn)為undefined writable:能否修改屬性的值,默認(rèn)值為true enumerable:能否通過(guò)for-in循環(huán)返回屬性。默認(rèn)為ture configurable:能否通過(guò)delete刪除屬性從而重新定義屬性,能否修改屬性的特性,能否把屬性修改為訪問(wèn)器屬性,默認(rèn)為true.
上面對(duì)類的方法修飾 實(shí)際是通過(guò) descriptor.value 拿到其方法,在進(jìn)行包裝返回
同時(shí)也可以直接修改descriptor上的其他屬性或者返回一個(gè)新的descriptor
3. 針對(duì) 訪問(wèn)操作符的裝飾class test { //@nonenumerable get kidCount() { return 111 } } function disWirte(target, name, descriptor) { descriptor.writable = false return descriptor } let p = new test() console.log(p.kidCount) p.kidCount = 222n descriptor; // 拋出異常 // TypeError: Cannot set property kidCount of #4. 修飾傳參which has only a getter
class Apes { @say("可以說(shuō)漢語(yǔ)了") say() { console.log("厵爨癵驫寶麣纞虋讟钃鸜麷鞻韽顟顠饙饙騳騱龗鱻爩麤") } } // 修飾方法并傳遞參數(shù) function say(str) { return function(className, propName, descriptor) { descriptor.value = function() { console.log(str) } return descriptor } }
通過(guò)柯里化的方式傳遞參數(shù)
應(yīng)用 1. 應(yīng)用在斐波那契數(shù)列計(jì)算中const memory = () => { const cache = {} //緩存池 return (target, name, descriptor) => { // 原方法 const method = descriptor.value // 包裹原方法 descriptor.value = function(key) { if (cache[key]) { return cache[key] } const ret = method.apply(target, [key]) cache[key] = ret return ret } return descriptor } } let count = 0 class Test { @memory() fb(n) { count++ if (n === 1) return 1 if (n === 2) return 1 return this.fb(n - 1) + this.fb(n - 2) } } const t = new Test() console.log(t.fb(10)) console.log(count)2. 訪問(wèn)操作符-set 上作類型檢查
class test { constructor() { this.a = 1 } get a() { return this.a } @check("number") set a(v) { return v } } function check(type) { return function(target, prop, descriptor) { let v = descriptor.value return { enumerable: true, configurable: true, get: function() { return v }, set: function(c) { var curType = typeCheck(c) if (curType !== type) { throw `${prop}必須為${type}類型` } v = c } } } } function typeCheck(c) { if (c === undefined) { return undefined } if (c === null) { return null } let type = typeof c if (type === "object") { return c.constructor == Array ? "array" : "object" } return type } let t = new test(11) t.a = 2 console.log(t.a) // 2 t.a = [] console.log(t.a) // throw a必須為number類型
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/106576.html
摘要:中的裝飾在前端編程中,我們可以采用裝飾器,來(lái)實(shí)現(xiàn)編程。裝飾器使用我們先建立一個(gè)簡(jiǎn)單的類,這個(gè)類的作用,就是在執(zhí)行的時(shí)候,打印出。至此,一個(gè)簡(jiǎn)單的裝飾器范例已經(jīng)完成。 什么是裝飾器? 了解AOP 在學(xué)習(xí)js中的裝飾器之間,我們需要了解AOP(面向切面編程)編程思想。 AOP是一種可以通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)在不修改源代碼的情況下給程序動(dòng)態(tài)統(tǒng)一添加功能的一種技術(shù)。AOP實(shí)際是Go...
摘要:項(xiàng)目地址項(xiàng)目主頁(yè)基于和注解的輕量級(jí)容器,提供了依賴注入面向切面編程及異常處理等功能??稍谌我夤こ讨幸耄且粋€(gè)框架無(wú)關(guān)的容器。模塊不依賴于任何框架,并與現(xiàn)有框架庫(kù)類等保持兼容。 Rockerjs Core 項(xiàng)目地址 項(xiàng)目主頁(yè) 基于 TypeScript 和注解的輕量級(jí)IoC容器,提供了依賴注入、面向切面編程及異常處理等功能。Rockerjs Core可在任意工程中引入,是一個(gè)框架無(wú)...
摘要:項(xiàng)目地址項(xiàng)目主頁(yè)基于和注解的輕量級(jí)容器,提供了依賴注入面向切面編程及異常處理等功能??稍谌我夤こ讨幸耄且粋€(gè)框架無(wú)關(guān)的容器。模塊不依賴于任何框架,并與現(xiàn)有框架庫(kù)類等保持兼容。 Rockerjs Core 項(xiàng)目地址 項(xiàng)目主頁(yè) 基于 TypeScript 和注解的輕量級(jí)IoC容器,提供了依賴注入、面向切面編程及異常處理等功能。Rockerjs Core可在任意工程中引入,是一個(gè)框架無(wú)...
摘要:下裝飾者的實(shí)現(xiàn)了解了裝飾者模式和的概念之后,我們寫一段能夠兼容的代碼來(lái)實(shí)現(xiàn)裝飾者模式原函數(shù)拍照片定義函數(shù)裝飾函數(shù)加濾鏡用裝飾函數(shù)裝飾原函數(shù)這樣我們就實(shí)現(xiàn)了抽離拍照與濾鏡邏輯,如果以后需要自動(dòng)上傳功能,也可以通過(guò)函數(shù)來(lái)添加。 showImg(https://segmentfault.com/img/bVbueyz?w=852&h=356); 什么是裝飾者模式 當(dāng)我們拍了一張照片準(zhǔn)備發(fā)朋友...
摘要:裝飾器顧名思義就是裝飾某種東西的方法,可以用來(lái)裝飾屬性變量函數(shù)類實(shí)例方法本質(zhì)上是個(gè)函數(shù)。以符開(kāi)頭,函數(shù)名稱自擬。愛(ài)吃蘋果裝飾器裝飾類愛(ài)吃蘋果結(jié)果是這個(gè)類本身就可以通過(guò)修改類的屬性增加屬性被裝飾的對(duì)象可以使用多個(gè)裝飾器。 @Decorator 裝飾器是es7的語(yǔ)法,這個(gè)方法對(duì)于面向切面編程有了更好的詮釋,在一些情境中可以使用,比如路人A的代碼實(shí)現(xiàn)了一需求,路人B希望用A的方法來(lái)實(shí)現(xiàn)一個(gè)新...
閱讀 3790·2021-11-24 09:39
閱讀 2686·2019-08-30 15:54
閱讀 1229·2019-08-30 13:01
閱讀 3518·2019-08-28 18:30
閱讀 1687·2019-08-26 17:44
閱讀 3646·2019-08-26 11:31
閱讀 2497·2019-08-26 10:40
閱讀 1345·2019-08-26 10:27