許多面向對象的語言都有修飾起函數,用來修改類的行爲函數
@testable
class MyTestableClass{
}
function testable(target){
target.isTestable = true
}
MyTestableClass.isTestable // true
複製代碼
上面代碼中,@testable就是修飾器。它修改了MyTestableClass這個類的行爲,爲它加上了靜態屬性isTestable。testable函數的參數target是MyTestableClass類自己。也就是說,修飾器是一個對類進行處理的函數。修飾器函數的第一個參數,就是所要修飾的目標類ui
若是以爲一個參數不夠用,能夠在修飾器外面再封裝一層函數this
function testable(isTestable){
return function(target){
target.isTestable = isTestable
}
}
@testable(true)
class MyTestableClass{}
MyTestableClass.isTestable // true
@testable(false)
class MyTestableClass{}
MyTestableClass.isTestable // false
複製代碼
修飾器對類的行爲的改變,是代碼編譯時發生的,而不是在運行時。lua
若是想添加實例屬性,能夠經過目標類的prototype對象操做spa
function testable(target){
target.prototype.isTestable = true
}
@testable
class MyTestableClass{}
let obj = new MyTestableClass();
obj.isTestable // true
複製代碼
修飾器不只能夠修飾類,還能夠修飾類的屬性prototype
class Person{
@readonly
name() {return `${this.first} ${this.last}`}
}
複製代碼
修飾器readonly用來修飾 類 的name方法,修飾器readonly一共能夠接受三個參數。code
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
複製代碼
若是同一個方法有多個修飾器,會像剝洋蔥同樣,先從外到內進入,而後由內向外執行。ip
外層修飾器@dec(1)
先進入,可是內層修飾器@dec(2)
先執行。ci