目錄
1、裝飾器是什么?
2、裝飾器怎么用?
類裝飾
方法/屬性裝飾
3、裝飾器工廠
4、執行順序
5、應用場景
1、裝飾器是什么?
裝飾器是一種特殊型別的宣告,它能夠被附加到類宣告,方法, 訪問符,屬性或引數上,是一種在不改變原類和使用繼承的情況下,動態地擴展物件功能,
裝飾器本質不是什么高大上的結構,就是一個普通的函式,@expression 的形式其實是Object.defineProperty的語法糖,expression求值后必須也是一個函式,它會在運行時被呼叫,被裝飾的宣告資訊做為引數傳入,
2、裝飾器怎么用?
類的裝飾器可以裝飾:
- 類
- 方法/屬性
- 引數
- 訪問器
類裝飾
如下,我們宣告一個Person類
class Person{
constructor(name) {
this.name = name
}
}
接著,創建一個實體物件
let person = new Person("leo");
console.log(person.name); // leo
以上只是一個使用類的簡單例子,真實場景下,類中可能會有許多屬性與方法,其也是我們使用類的目的,可以通過它,構造一類擁有相同屬性與方法的實體物件,
那么當我們宣告了類之后,假如某個程式片段需要使用該類來構造實體物件,且除了該類中的屬性與方法,我們需要額外新增屬性或方法,這時就可以使用裝飾器來擴展原有的功能,
實體
// @裝飾的必須是函式,該處為addAge
function addAge(target) { // 在修飾類時,此處target為Person這個類
target.prototype.age = 18;
}
// 類修飾,擴展功能(添加屬性age,值為18)
@addAge
class Person{
constructor(name) {
this.name = name;
}
}
let person = new Person('leo');
console.log(person.name); // leo
console.log(person.age); // 18
在以上實體中,Person類中并不存在age屬性,當裝飾器作為修飾類的時候,會把構造器傳遞進去,target.prototype.age 就是在每一個實體化物件上面添加一個 age 屬性,
由于裝飾器是運算式,我們也可以在裝飾器后面再添加個引數
function addAge(number) {
return function(target){
target.prototype.age = number;
}
}
@addAge(18)
class Person{
constructor(name) {
this.name = name;
}
}
let person = new Person('leo');
console.log(person.name); // leo
console.log(person.age); // 18
方法/屬性裝飾
同樣,裝飾器可以用于修飾類的方法,這時候裝飾器函式接收的引數變成了:
- target:物件的原型
- propertyKey:方法的名稱
- descriptor:方法的屬性描述符
看到這,有沒有一絲熟悉感?這三個屬性實際就是Object.defineProperty的三個引數,如果是類的屬性,則不傳遞第三個引數,
實體
// 宣告裝飾器修飾方法/屬性
function method(target, propertyKey, descriptor) {
console.log(target);
console.log("propertyKey:" + propertyKey);
console.log("descriptor:" + JSON.stringify(descriptor) + "\n\n");
descriptor.writable = false; // 默認為true,設定為false,則修飾的方法不可修改
};
function property(target, propertyKey) {
console.log("target:", target)
console.log("propertyKey:", propertyKey)
}
class Person{
constructor() {
this.name = 'leo';
}
@method
sayHi(){
return 'Hi' + this.name;
}
@method
static run(){
return 'static method';
}
}
const obj = new Person();
控制臺列印如下
Person類中并沒有列印的邏輯,這些是裝飾器帶來的擴展功能,我們嘗試修改sayHi方法,如下
obj.sayHi = function(){
return "是否允許修改?"
}
此時控制臺報錯
因為我們在裝飾器中設定 descriptor.writable = false,修飾某方法時,該方法只讀,不允許修改,
3、裝飾器工廠
如果想要傳遞引數,使裝飾器變成類似工廠函式,只需要在裝飾器函式內部再返回一個函式即可,如上面例子
function addAge(number) {
return function(target){
target.prototype.age = number;
}
}
@addAge(18)
class Person{
constructor(name) {
this.name = name;
}
}
let person = new Person('leo');
console.log(person.name); // leo
console.log(person.age); // 18
4、執行順序
當多個裝飾器應用于一個宣告上,將由上至下依次對裝飾器運算式求值,求值的結果會被當作函式,由下至上依次呼叫,如下
function f() {
console.log("f(): 我是f()");
return function (target, propertyKey, descriptor) {
console.log("f(): called");
}
}
function g() {
console.log("g(): 我是g()");
return function (target, propertyKey, descriptor) {
console.log("g(): called");
}
}
class Person {
@f()
@g()
method() {}
}
控制臺列印如下

運算式由上往下執行,而求值的結果函式由下往上呼叫,
5、應用場景
使用裝飾器存在兩個顯著的優點:
- 代碼可讀性變強,裝飾器命名相當于一個注釋
- 不改變原有代碼情況下,對原有功能進行擴展
借助裝飾器的特性,除了提高可讀性之外,對已經存在的類,可以通過裝飾器在不改變原本代碼的情況下,對原來功能進行擴展,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/404378.html
標籤:其他
下一篇:學習jQuery的第一天
