淺談ES7的修飾器

人間失格發表於2018-07-11

類的修飾

許多物件導向的語言都有修飾起函式,用來修改類的行為

@testable
class MyTestableClass{
    
}

function testable(target){
    target.isTestable = true
}

MyTestableClass.isTestable  // true
複製程式碼

上面程式碼中,@testable就是修飾器。它修改了MyTestableClass這個類的行為,為它加上了靜態屬性isTestable。testable函式的引數target是MyTestableClass類本身。也就是說,修飾器是一個對類進行處理的函式。修飾器函式的第一個引數,就是所要修飾的目標類

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

function testable(isTestable){
    return function(target){
        target.isTestable = isTestable
    }
}

@testable(true)
class MyTestableClass{}
MyTestableClass.isTestable  // true

@testable(false)
class MyTestableClass{}
MyTestableClass.isTestable  // false
複製程式碼

修飾器對類的行為的改變,是程式碼編譯時發生的,而不是在執行時。

如果想新增例項屬性,可以通過目標類的prototype物件操作

function testable(target){
    target.prototype.isTestable = true
}

@testable
class MyTestableClass{}

let obj = new MyTestableClass();
obj.isTestable  // true
複製程式碼

方法的修飾

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

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)
複製程式碼

修飾器第一個引數是類的原型物件,上例是Person.prototype,修飾器的本意是要 修飾類的例項,但是這個例項還沒有生成,所以智慧去修飾原型,第二個引數是所要修飾的屬性名,第三個引數是該屬性的描述物件。

多個修飾器的執行

function dec(id){
	// 此處是按照修飾順序執行
    console.log('evaluated', id);
    // 返回的函式則是按照反順序執行。
    return (target, property, descriptor) => console.log('executed', id)
}

class Example{
    @dec(1)
    @dec(2)
   	method(){}
}
// evaluated 1
// evaluated 2
// executed 2
// executed 1
複製程式碼

如果同一個方法有多個修飾器,會像剝洋蔥一樣,先從外到內進入,然後由內向外執行。

外層修飾器@dec(1)先進入,但是內層修飾器@dec(2)先執行。

相關文章