摘要:在的中,定義了種不同裝飾器的接口,其中裝飾類以及裝飾類方法的接口定義如下所示下面對這兩種情況進行解析。作用于類的裝飾器當裝飾的對象是類時,我們操作的就是這個類本身。相關鏈接中的裝飾器裝飾器場景實戰修飾器
隨著 ES6 和 TypeScript 中類的引入,在某些場景需要在不改變原有類和類屬性的基礎上擴展些功能,這也是裝飾器出現的原因。
裝飾器簡介作為一種可以動態增刪功能模塊的模式(比如 redux 的中間件機制),裝飾器同樣具有很強的動態靈活性,只需在類或類屬性之前加上 @方法名 就完成了相應的類或類方法功能的變化。
不過裝飾器模式仍處于第 2 階段提案中,使用它之前需要使用 babel 模塊 transform-decorators-legacy 編譯成 ES5 或 ES6。
在 TypeScript 的 lib.es5.d.ts 中,定義了 4 種不同裝飾器的接口,其中裝飾類以及裝飾類方法的接口定義如下所示:
declare type ClassDecorator =(target: TFunction) => TFunction | void; declare type MethodDecorator = (target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor ) => TypedPropertyDescriptor | void;
下面對這兩種情況進行解析。
作用于類的裝飾器當裝飾的對象是類時,我們操作的就是這個類本身。
@log class MyClass { } function log(target) { // 這個 target 在這里就是 MyClass 這個類 target.prototype.logger = () => `${target.name} 被調用` } const test = new MyClass() test.logger() // MyClass 被調用
由于裝飾器是表達式,我們也可以在裝飾器后面再添加提個參數:
@log("hi") class MyClass { } function log(text) { return function(target) { target.prototype.logger = () => `${text},${target.name} 被調用` } } const test = new MyClass() test.logger() // hello,MyClass 被調用
在使用 redux 中,我們最常使用 react-redux 的寫法如下:
@connect(mapStateToProps, mapDispatchToProps) export default class MyComponent extends React.Component {}
經過上述分析,我們知道了上述寫法等價于下面這種寫法:
class MyComponent extends React.Component {} export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)作用于類方法的裝飾器
與裝飾類不同,對類方法的裝飾本質是操作其描述符。可以把此時的裝飾器理解成是 Object.defineProperty(obj, prop, descriptor) 的語法糖,看如下代碼:
class C { @readonly(false) method() { console.log("cat") } } function readonly(value) { return function (target, key, descriptor) { // 此處 target 為 C.prototype; key 為 method; // 原 descriptor 為:{ value: f, enumarable: false, writable: true, configurable: true } descriptor.writable = value return descriptor } } const c = new C() c.method = () => console.log("dog") c.method() // cat
可以看到裝飾器函數接收的三個參數與 Object.defineProperty 是完全一樣的,具體實現可以看 babel 轉化后的代碼,主要實現如下所示:
var C = (function() { class C { method() { console.log("cat") } } var temp temp = readonly(false)(C.prototype, "method", temp = Object.getOwnPropertyDescriptor(C.prototype, "method")) || temp // 通過 Object.getOwnPropertyDescriptor 獲取到描述符傳入到裝飾器函數中 if (temp) Object.defineProperty(C.prototype, "method", temp) return C })()
再將再來看看如果有多個裝飾器作用于同一個方法上呢?
class C { @readonly(false) @log method() { } }
經 babel 轉化后的代碼如下:
desc = [readonly(false), log] .slice() .reverse() .reduce(function(desc, decorator) { return decorator(target, property, desc) || desc; }, desc);
可以清晰地看出,經過 reverse 倒序后,裝飾器方法會至里向外執行。
相關鏈接javascript-decorators
Javascript 中的裝飾器
JS 裝飾器(Decorator)場景實戰
修飾器
Babel
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93493.html
摘要:本套課程包含兩大部分,第一部分是基礎部分,也是重要部分,參考官方文檔結構,針對內容之間的關聯性和前后順序進行合理調整。 showImg(https://segmentfault.com/img/bVbpBA0?w=1460&h=400); 講師簡介: iview 核心開發者,iview-admin 作者,百萬級虛擬渲染表格組件 vue-bigdata-table 作者。目前就職于知名互...
摘要:第二部分源碼解析接下是應用多個第二部分對于一個方法應用了多個,比如會編譯為在第二部分的源碼中,執行了和操作,由此我們也可以發現,如果同一個方法有多個裝飾器,會由內向外執行。有了裝飾器,就可以改寫上面的代碼。 Decorator 裝飾器主要用于: 裝飾類 裝飾方法或屬性 裝飾類 @annotation class MyClass { } function annotation(ta...
摘要:歷史裝飾器這個概念三年多前被首次提出。在版本年中發布了對裝飾器的支持以及許多特性。有不同的安全級別需要考慮裝飾器不應該意外泄漏私有名稱。你可以測試裝飾器的新語法,并向提案的作者們提出反饋意見。 原文地址:https://babeljs.io/blog/2018/...原文作者:Nicolò Ribaudo Babel 7.1.0最終支持新的裝飾器提案,可以通過@babel/plugin...
摘要:裝飾器我們為啥要討論元素注入器而不是裝飾器這是因為會把元素注入器依賴解析過程限制在當前組件視圖內。但是一旦使用了裝飾器,整個依賴解析過程就會在第一階段完成后停止解析,也就是說,元素注入器只在組件視圖內解析依賴,然后就停止解析工作。 原文鏈接:A curious case of the @Host decorator and Element Injectors in Angular 我...
摘要:所以這是一篇插隊的文章,用于去理解中的裝飾器和概念。因此,該的作用就是根據入參返回具體的描述符。其次局部來看,裝飾器具體應用表達式是,其函數簽名和是一模一樣。等裝飾器語法,是和直接使用是等效等價的。 ================前言=================== 初衷:以系列故事的方式展現 MobX 源碼邏輯,盡可能以易懂的方式講解源碼; 本系列文章: 《【用故事解...
閱讀 1893·2021-11-22 09:34
閱讀 3029·2021-09-28 09:35
閱讀 13436·2021-09-09 11:34
閱讀 3600·2019-08-29 16:25
閱讀 2829·2019-08-29 15:23
閱讀 2043·2019-08-28 17:55
閱讀 2433·2019-08-26 17:04
閱讀 3050·2019-08-26 12:21