我正在嘗試了解打字稿裝飾器。
在這個例子中,為什么decorator1() 在應用于類方法時需要方括號而decorator2 不需要?我對 TS 裝飾器的了解還不足以區分這兩種型別的裝飾器,因此我們不勝感激。
https://codesandbox.io/s/typescript-decorator-forked-v3u6q?file=/src/index.ts
function decorate1() {
console.log("decorate1(): factory evaluated");
return function (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
console.log("decorate1(): called");
};
}
function decorate2(target, key, descriptor) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
// Call the original method
console.log("calling decorate2 function");
const result = original.apply(this, args);
console.log("decorate2 returned", result);
return result;
};
return descriptor;
}
class ExampleClass {
@decorate1()
@decorate2
method() {
return "something";
}
}
const example = new ExampleClass();
example.method();
uj5u.com熱心網友回復:
首先,請務必記住,裝飾器是 TypeScript 中的一項實驗性功能,相應的 JavaScript 提議功能已發生很大變化,并且處于TC39 提議流程的第 2 階段。因此,如果您還沒有開始依賴它們,最好避免使用它們。如果裝飾器提案達到第 3 階段,TypeScript 將修改 TS 功能以符合它,這可能是一個重大更改。
總結:裝飾器是接受特定引數并回傳特定值的函式;您可以使用任何運算式進行裝飾,只要它充當裝飾器即可。括號不是裝飾器宣告語法的一部分;它們是運算式的一部分。如果您撰寫,@foo那么您將foo用作裝飾器。如果你寫,@bar()那么你是在使用bar(),而不是bar,作為裝飾器。它就像const baz = bar()然后用 裝飾@baz。
無論如何,您正在談論方法裝飾器。方法裝飾器是一個接受三個引數的函式:類原型或建構式(取決于static被裝飾的方法的性質);方法名稱和方法的屬性描述符。它要么不回傳任何內容,要么回傳一個新的屬性描述符。
所以這是一個方法裝飾器:
const decorator = (
target: any, key: PropertyKey, descriptor: PropertyDescriptor
) => {
console.log("decorator", key);
}
您可以通過在方法宣告之前放置裝飾器宣告來裝飾類方法。 裝飾器宣告看起來像@后跟裝飾器運算式。這可以是任何運算式,只要它可以充當裝飾器;在這種情況下,符合上述規則的函式:
class Foo {
@decorator
method1() { } //"decorator", "method1"
}
您正在使用運算式進行裝飾decorator。請注意,后面沒有括號decorator。如果你寫decorator()你會呼叫 decorator(沒有引數,無論如何這是錯誤的)并且由于decorator()評估為undefined(它不回傳定義的值),你將用 裝飾undefined,而undefined不是裝飾器。
如果裝飾器需要更多資訊才能運行,從概念上講,您希望它采用比所需三個引數更多的引數,但這是不允許的。什么是允許的是讓一個函式,它的額外資訊,并回傳一個裝飾。這是一個回傳裝飾器的函式:
const fnReturningDecorator = (name: string) => (
target: any, key: PropertyKey, descriptor: PropertyDescriptor
) => {
console.log("fnReturningDecorator", name, key);
}
下面是你如何使用它來裝飾一個方法:
class Foo {
@fnReturningDecorator("hello")
method2() { } // "fnReturningDecorator", "hello", "method2"
}
您正在使用運算式進行裝飾fnReturningDecorator("hello")。請注意,您必須fnReturningDecorator使用其string引數進行呼叫,然后使用回傳的裝飾器進行裝飾。如果你寫fnReturningDecorator的時候沒有引數,你會用一個函式來裝飾,它接受一個string引數并回傳一個函式,這不是一個裝飾器。同樣,回傳裝飾器的函式本身并不是裝飾器。
這相當于:
const hello = fnReturningDecorator("hello");
class Foo {
@hello
method2() { } // "fnReturningDecorator", "hello", "method2"
}
所以括號沒有什么特別的。括號只是函式呼叫,這樣你就可以得到一個裝飾器;它們不是裝飾器語法的一部分。
同樣,任何評估為適當裝飾器的運算式都可以使用。作為最后一個示例,這是一個具有裝飾器屬性的物件:
const objHoldingDecorator = {
decorator: (
target: any, key: PropertyKey, descriptor: PropertyDescriptor
) => {
console.log("objHoldingDecorator", key);
}
}
現在當我們想用裝飾器裝飾時,我們這樣做:
class Foo {
@objHoldingDecorator.decorator
method3() { } // "objHoldingDecorator", "method3"
}
同樣,沒有括號,但這次我們有一個點。裝飾者是objHoldingDecorator.decorator; 如果您嘗試使用 justobjHoldingDecorator進行裝飾,您將使用不可呼叫的物件進行裝飾,而那不是裝飾器。
Playground 鏈接到代碼
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/390798.html
