<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        怎樣在項目中使用JS裝飾器函數

        來源:懂視網 責編:小采 時間:2020-11-27 19:40:04
        文檔

        怎樣在項目中使用JS裝飾器函數

        怎樣在項目中使用JS裝飾器函數:這次給大家帶來怎樣在項目中使用JS裝飾器函數,怎在項目中使用JS裝飾器函數的注意事項有哪些,下面就是實戰案例,一起來看一下。在 ES6 中增加了對類對象的相關定義和操作(比如 class 和 extends ),這就使得我們在多個不同類之間共享或者擴展一些方法或者
        推薦度:
        導讀怎樣在項目中使用JS裝飾器函數:這次給大家帶來怎樣在項目中使用JS裝飾器函數,怎在項目中使用JS裝飾器函數的注意事項有哪些,下面就是實戰案例,一起來看一下。在 ES6 中增加了對類對象的相關定義和操作(比如 class 和 extends ),這就使得我們在多個不同類之間共享或者擴展一些方法或者

        這次給大家帶來怎樣在項目中使用JS裝飾器函數,怎在項目中使用JS裝飾器函數的注意事項有哪些,下面就是實戰案例,一起來看一下。

        在 ES6 中增加了對類對象的相關定義和操作(比如 class 和 extends ),這就使得我們在多個不同類之間共享或者擴展一些方法或者行為的時候,變得并不是那么優雅。這個時候,我們就需要一種更優雅的方法來幫助我們完成這些事情。

        什么是裝飾器

        Python 的裝飾器

        在面向對象(OOP)的設計模式中,decorator被稱為裝飾模式。OOP的裝飾模式需要通過繼承和組合來實現,而Python除了能支持 OOP 的 decorator 外,直接從語法層次支持 decorator。

        如果你熟悉 python 的話,對它一定不會陌生。那么我們先來看一下 python 里的裝飾器是什么樣子的吧:

        def decorator(f):
         print "my decorator"
         return f
        @decorator
        def myfunc():
         print "my function"
        myfunc()
        # my decorator
        # my function

        這里的 @decorator 就是我們說的裝飾器。在上面的代碼中,我們利用裝飾器給我們的目標方法執行前打印出了一行文本,并且并沒有對原方法做任何的修改。代碼基本等同于:

        def decorator(f):
         def wrapper():
         print "my decorator"
         return f()
         return wrapper
        def myfunc():
         print "my function"
        myfunc = decorator(myfuc)

        通過代碼我們也不難看出,裝飾器 decorator 接收一個參數,也就是我們被裝飾的目標方法,處理完擴展的內容以后再返回一個方法,供以后調用,同時也失去了對原方法對象的訪問。當我們對某個應用了裝飾以后,其實就改變了被裝飾方法的入口引用,使其重新指向了裝飾器返回的方法的入口點,從而來實現我們對原函數的擴展、修改等操作。

        ES7 的裝飾器

        ES7 中的 decorator 同樣借鑒了這個語法糖,不過依賴于 ES5 的 Object.defineProperty 方法 。

        Object.defineProperty

        Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 并返回這個對象。

        該方法允許精確添加或修改對象的屬性。通過賦值來添加的普通屬性會創建在屬性枚舉期間顯示的屬性(for...in 或 Object.keys 方法), 這些值可以被改變,也可以被刪除。這種方法允許這些額外的細節從默認值改變。默認情況下,使用 Object.defineProperty() 添加的屬性值是不可變的。

        語法

        Object.defineProperty(obj, prop, descriptor)
        1. obj:要在其上定義屬性的對象。

        2. prop:要定義或修改的屬性的名稱。

        3. descriptor:將被定義或修改的屬性描述符。

        4. 返回值:被傳遞給函數的對象。

        在ES6中,由于 Symbol類型 的特殊性,用 Symbol類型 的值來做對象的key與常規的定義或修改不同,而Object.defineProperty 是定義 key為 Symbol 的屬性的方法之一。

        屬性描述符

        對象里目前存在的屬性描述符有兩種主要形式:數據描述符和存取描述符。

        數據描述符是一個具有值的屬性,該值可能是可寫的,也可能不是可寫的。

      1. 存取描述符是由 getter-setter 函數對描述的屬性。

      2. 描述符必須是這兩種形式之一;不能同時是兩者。

      3. 數據描述符和存取描述符均具有以下可選鍵值:

        configurable

        當且僅當該屬性的 configurable 為 true 時,該屬性描述符才能夠被改變,同時該屬性也能從對應的對象上被刪除。默認為 false。

        enumerable

        enumerable定義了對象的屬性是否可以在 for...in 循環和 Object.keys() 中被枚舉。

        當且僅當該屬性的 enumerable 為 true 時,該屬性才能夠出現在對象的枚舉屬性中。默認為 false。
        數據描述符同時具有以下可選鍵值:

        value

        該屬性對應的值。可以是任何有效的 JavaScript 值(數值,對象,函數等)。默認為 undefined。

        writable

        當且僅當該屬性的 writable 為 true 時,value 才能被賦值運算符改變。默認為 false。

        存取描述符同時具有以下可選鍵值:

        get

        一個給屬性提供 getter 的方法,如果沒有 getter 則為 undefined。該方法返回值被用作屬性值。默認為 undefined。

        set

        一個給屬性提供 setter 的方法,如果沒有 setter 則為 undefined。該方法將接受唯一參數,并將該參數的新值分配給該屬性。默認為 undefined。

        如果一個描述符不具有value,writable,get 和 set 任意一個關鍵字,那么它將被認為是一個數據描述符。如果一個描述符同時有(value或writable)和(get或set)關鍵字,將會產生一個異常。
        用法

        類的裝飾

        @testable
        class MyTestableClass {
         // ...
        }
        function testable(target) {
         target.isTestable = true;
        }
        MyTestableClass.isTestable // true

        上面代碼中,@testable 就是一個裝飾器。它修改了 MyTestableClass這 個類的行為,為它加上了靜態屬性isTestable。testable 函數的參數 target 是 MyTestableClass 類本身。

        基本上,裝飾器的行為就是下面這樣。

        @decorator
        class A {}
        // 等同于
        class A {}
        A = decorator(A) || A;

        也就是說,裝飾器是一個對類進行處理的函數。裝飾器函數的第一個參數,就是所要裝飾的目標類。

        如果覺得一個參數不夠用,可以在裝飾器外面再封裝一層函數。

        function testable(isTestable) {
         return function(target) {
         target.isTestable = isTestable;
         }
        }
        @testable(true)
        class MyTestableClass {}
        MyTestableClass.isTestable // true
        @testable(false)
        class MyClass {}
        MyClass.isTestable // false

        上面代碼中,裝飾器 testable 可以接受參數,這就等于可以修改裝飾器的行為。

        注意,裝飾器對類的行為的改變,是代碼編譯時發生的,而不是在運行時。這意味著,裝飾器能在編譯階段運行代碼。也就是說,裝飾器本質就是編譯時執行的函數。

        前面的例子是為類添加一個靜態屬性,如果想添加實例屬性,可以通過目標類的 prototype 對象操作。

        下面是另外一個例子。

        // mixins.js
        export function mixins(...list) {
         return function (target) {
         Object.assign(target.prototype, ...list)
         }
        }
        // main.js
        import { mixins } from './mixins'
        const Foo = {
         foo() { console.log('foo') }
        };
        @mixins(Foo)
        class MyClass {}
        let obj = new MyClass();
        obj.foo() // 'foo'

        上面代碼通過裝飾器 mixins,把Foo對象的方法添加到了 MyClass 的實例上面。

        方法的裝飾

        裝飾器不僅可以裝飾類,還可以裝飾類的屬性。

        class Person {
         @readonly
         name() { return `${this.first} ${this.last}` }
        }

        上面代碼中,裝飾器 readonly 用來裝飾“類”的name方法。

        裝飾器函數 readonly 一共可以接受三個參數。

        function readonly(target, name, descriptor){
         // descriptor對象原來的值如下
         // {
         // value: specifiedFunction,
         // enumerable: false,
         // configurable: true,
         // writable: true
         // };
         descriptor.writable = false;
         return descriptor;
        }
        readonly(Person.prototype, 'name', descriptor);
        // 類似于
        Object.defineProperty(Person.prototype, 'name', descriptor);
      4. 裝飾器第一個參數是 類的原型對象,上例是 Person.prototype,裝飾器的本意是要“裝飾”類的實例,但是這個時候實例還沒生成,所以只能去裝飾原型(這不同于類的裝飾,那種情況時target參數指的是類本身);

      5. 第二個參數是 所要裝飾的屬性名

      6. 第三個參數是 該屬性的描述對象

      7. 另外,上面代碼說明,裝飾器(readonly)會修改屬性的 描述對象(descriptor),然后被修改的描述對象再用來定義屬性。

        函數方法的裝飾

        裝飾器只能用于類和類的方法,不能用于函數,因為存在函數提升。

        另一方面,如果一定要裝飾函數,可以采用高階函數的形式直接執行。

        function doSomething(name) {
         console.log('Hello, ' + name);
        }
        function loggingDecorator(wrapped) {
         return function() {
         console.log('Starting');
         const result = wrapped.apply(this, arguments);
         console.log('Finished');
         return result;
         }
        }
        const wrapped = loggingDecorator(doSomething);

        core-decorators.js

        core-decorators.js是一個第三方模塊,提供了幾個常見的裝飾器,通過它可以更好地理解裝飾器。

        @autobind

        autobind 裝飾器使得方法中的this對象,綁定原始對象。

        @readonly

        readonly 裝飾器使得屬性或方法不可寫。

        @override

        override 裝飾器檢查子類的方法,是否正確覆蓋了父類的同名方法,如果不正確會報錯。

        import { override } from 'core-decorators';
        class Parent {
         speak(first, second) {}
        }
        class Child extends Parent {
         @override
         speak() {}
         // SyntaxError: Child#speak() does not properly override Parent#speak(first, second)
        }
        // or
        class Child extends Parent {
         @override
         speaks() {}
         // SyntaxError: No descriptor matching Child#speaks() was found on the prototype chain.
         //
         // Did you mean "speak"?
        }

        @deprecate (別名@deprecated)

        deprecate 或 deprecated 裝飾器在控制臺顯示一條警告,表示該方法將廢除。

        import { deprecate } from 'core-decorators';
        class Person {
         @deprecate
         facepalm() {}
         @deprecate('We stopped facepalming')
         facepalmHard() {}
         @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' })
         facepalmHarder() {}
        }
        let person = new Person();
        person.facepalm();
        // DEPRECATION Person#facepalm: This function will be removed in future versions.
        person.facepalmHard();
        // DEPRECATION Person#facepalmHard: We stopped facepalming
        person.facepalmHarder();
        // DEPRECATION Person#facepalmHarder: We stopped facepalming
        //
        // See http://knowyourmeme.com/memes/facepalm for more details.
        //

        @suppressWarnings

        suppressWarnings 裝飾器抑制 deprecated 裝飾器導致的 console.warn() 調用。但是,異步代碼發出的調用除外。

        使用場景

        裝飾器有注釋的作用

        @testable
        class Person {
         @readonly
         @nonenumerable
         name() { return `${this.first} ${this.last}` }
        }

        有了裝飾器,就可以改寫上面的代碼。裝飾

        @connect(mapStateToProps, mapDispatchToProps)
        export default class MyReactComponent extends React.Component {}

        相對來說,后一種寫法看上去更容易理解。

        新功能提醒或權限

        菜單點擊時,進行事件攔截,若該菜單有新功能更新,則彈窗顯示。

        /**
         * @description 在點擊時,如果有新功能提醒,則彈窗顯示
         * @param code 新功能的code
         * @returns {function(*, *, *)}
         */
         const checkRecommandFunc = (code) => (target, property, descriptor) => {
         let desF = descriptor.value; 
         descriptor.value = function (...args) {
         let recommandFuncModalData = SYSTEM.recommandFuncCodeMap[code];
         if (recommandFuncModalData && recommandFuncModalData.id) {
         setTimeout(() => {
         this.props.dispatch({type: 'global/setRecommandFuncModalData', recommandFuncModalData});
         }, 1000);
         }
         desF.apply(this, args);
         };
         return descriptor;
         };

        loading

        在 React 項目中,我們可能需要在向后臺請求數據時,頁面出現 loading 動畫。這個時候,你就可以使用裝飾器,優雅地實現功能。

        @autobind
        @loadingWrap(true)
        async handleSelect(params) {
         await this.props.dispatch({
         type: 'product_list/setQuerypParams',
         querypParams: params
         });
        }

        loadingWrap 函數如下:、

        export function loadingWrap(needHide) {
         const defaultLoading = (
         <p className="toast-loading">
         <Loading className="loading-icon"/>
         <p>加載中...</p>
         </p>
         );
         return function (target, property, descriptor) {
         const raw = descriptor.value;
         
         descriptor.value = function (...args) {
         Toast.info(text || defaultLoading, 0, null, true);
         const res = raw.apply(this, args);
         
         if (needHide) {
         if (get('finally')(res)) {
         res.finally(() => {
         Toast.hide();
         });
         } else {
         Toast.hide();
         }
         }
         };
         return descriptor;
         };
        }

        相信看了本文案例你已經掌握了方法,更多精彩請關注Gxl網其它相關文章!

        推薦閱讀:

        express + mock如何操作前后臺并行開發

        字符串+數組去重實戰案例解析

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        怎樣在項目中使用JS裝飾器函數

        怎樣在項目中使用JS裝飾器函數:這次給大家帶來怎樣在項目中使用JS裝飾器函數,怎在項目中使用JS裝飾器函數的注意事項有哪些,下面就是實戰案例,一起來看一下。在 ES6 中增加了對類對象的相關定義和操作(比如 class 和 extends ),這就使得我們在多個不同類之間共享或者擴展一些方法或者
        推薦度:
        標簽: 如何使用 js 項目
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 在免费jizzjizz在线播| 久久av免费天堂小草播放| 91精品国产免费久久久久久青草| 亚洲AV午夜福利精品一区二区 | 亚洲国产视频久久| 妞干网免费观看视频| 亚洲色成人WWW永久在线观看| 97在线观免费视频观看| 亚洲制服丝袜中文字幕| 成人免费无码大片A毛片抽搐 | 亚洲精品影院久久久久久| 嫩草成人永久免费观看| 久久精品国产亚洲AV麻豆网站| 91av视频免费在线观看| 亚洲AV综合色区无码二区偷拍| 成人无码区免费A片视频WWW| 亚洲国产精品嫩草影院 | 国产国拍亚洲精品mv在线观看 | 亚洲国产日韩一区高清在线| 久久久免费精品re6| 2020年亚洲天天爽天天噜| 国产成人精品123区免费视频| 日韩久久无码免费毛片软件| 亚洲成AV人片在线观看无码| 无码专区永久免费AV网站| 黄色一级视频免费| 亚洲AV无码成人精品区天堂| 毛片免费观看的视频| 免费精品视频在线| 亚洲精品国产手机| 午夜亚洲国产成人不卡在线| 亚洲免费观看视频| 亚洲女女女同性video| 亚洲欧洲日产国码无码网站| 精品熟女少妇AV免费观看| 一区二区三区AV高清免费波多| 亚洲一区影音先锋色资源| 国产无遮挡又黄又爽免费视频| 人妻在线日韩免费视频| 亚洲日韩精品无码专区加勒比 | 免费看少妇作爱视频|