Decorator裝飾器
阿新 • • 發佈:2019-01-22
Decorator 修飾器
說明
由 ES2017 引入了這個功能,他是一個函式用來修改類的行為,解決了不同類之間共享方法的問題
修飾器對類的行為的改變是在程式碼編譯時發生的,而不是在執行時,本質就是編譯時執行的函式
由於存在變數提升,使得修飾器不能用於函式(包括建構函式),類不會提升所以不會有這個問題
基本使用
@decorator
class Test {
constructor(name) {
this.name = name;
}
}
function decorator (target) {
// target 就是需要被修飾的類
target.prototype.getName = function () {
console.log(this.name);
}
}
const test = new Test('xiaobai');
test.getName(); // xiaobai
修飾器通過封裝後接受其他引數
function addMethod(methods) {
return function (target) {
Object.assign(target.prototype, methods);
}
}
const methods = {
change: function () {console.log('change')},
add: function () {},
delete: function () {},
get: function () {}
}
@addMethod(methods)
class Test {}
const test = new Test();
test.change(); // change
修飾器可以修飾類中的方法
作用在方法上的 decorator 接受的第一個引數是類的 prototype;作用到類上的 decorator 第一個引數表示類本身
Decorators 的本質是利用了 ES5 的 Object.defineProperty 屬性,所以它的三個引數:target name descriptor 跟 Object.defineProperty 的引數是一致的
Object.defineProperty 的引數詳解看這裡
- target:需要修飾的類的原型 prototype
- name: 需要修飾的類的屬性名或者方法名
- descriptor:被修改的屬性的描述符
- configurable:true | false 表示物件的屬性是否可以被刪除,以及除 writable 特性外的其他特性是否可以被修改
- enumerable:true | false 定義被修改的屬性是否可以是可以列舉的
- value:此屬性對應的值(數值、物件、函式等)
- writable:true | false 是否可以重寫此屬性
- initializer:如果修飾器修飾的是一個屬性不是方法,則會有這個屬性出現代替 value
function log (target, name, descriptor) {
// 保留舊的方法
const tempFn = descriptor.value;
// 重新定義方法
descriptor.value = function () {
console.log(`this is ${name} arguments: `, arguments);
// 借用舊的方法
return tempFn.apply(this, arguments);
}
return descriptor;
}
class Test {
constructor() {
this.list = []
}
@log
add (...items) {
this.list.push(...items);
}
}
var test = new Test();
test.add(12, 33, 222);
// 修飾器列印的日誌
// this is add arguments: (3) [12, 33, 222, callee: (...), Symbol(Symbol.iterator): function]
console.log(test); // {list: [12, 33, 222]}
修飾器修飾屬性
function change(target, name, descriptor) {
const tempVal = descriptor.initializer();
console.log(descriptor.initializer);
/*
initializer 函式型別
function initializer() {
return 'def value';
}
*/
descriptor.initializer = function () {
return 'change ' + tempVal;
}
return descriptor;
}
class Test {
@change
def = 'def value'
}
const test = new Test();
console.log(test.def) // change def value
修飾器可以疊加使用
function log (order) {
return function (target, name, descriptor) {
const tempFn = descriptor.value;
descriptor.value = function () {
console.log('decorator ' + order);
return tempFn.apply(this, arguments);
}
return descriptor;
}
}
class Test {
constructor() {
this.list = []
}
@log('top')
@log('bottom')
add (...items) {
this.list.push(...items);
}
}
var test = new Test();
test.add(12, 33, 222);
// decorator top | decorator bottom
console.log(test); // {list: [12, 33, 222]}