应用与方法的修饰器函数的返回值如果是特性对象时,则会作为方法的新的特性对象(这也要求此时返回值必须是个对象,否者会抛异常:TypeError: Property description must be an object)。
function wrap(target) {
return {
name: 'new Obj'
};
}
@wrap // 完全重定义了
class Person {
first = 'John'
last = 'Snow'
}
console.log(Person) ; // { name: 'new Obj' }
// Demo2
function wrapMethod(target, name, decorator) {
return {
value: true
};
}
class Person {
first = 'John'
last = 'Snow'
@wrapMethod
get fullName() {
return ${this.first} ${this.last};
}
}
var p = new Person();
console.log(p.fullName); // true
不过在这样做之前先看下使用[装饰模式](https://segmentfault.com/p/1210000009968000/read)的目的。
3. 如果修饰器函数没有返回值,则使用原来的特性对象/target (当修饰类时),所以修饰器函数的返回值是可选的。
4. 详细见[javascript-decorators#desugaring](https://github.com/wycats/javascript-decorators#desugaring)
## Issues
1. 修饰器函数什么时候执行?
在定义属性之前执行,修饰器用来修改方法的行为,必须在JS执行阶段动态的添加方法,并且在定义方法前执行修饰器函数。
```javascript
function readonly(target, name, descriptor) {
console.log('call readonly');
descriptor.writable = false;
return descriptor;
}
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}
console.log('after Person definition')
一、概念
标准定义:
二、语法
格式:
@表达式
承接上面的概念逐句解释:1. @后面跟任意表达式(A decorator is: an expression)
2. 表达式的值必须是个函数(that evaluates to a function)。
抛异常:TypeError: decorator is not a function
3. 修饰器函数的实参(a function that takes the target, name, and decorator descriptor as arguments)
根据修饰器使用的地方不同,修饰器函数的实参也不同:
1. 修饰类的修饰器函数实参只有一个参数,即类本身;
此时修饰器也称为“Leading decorators”, 头部修饰器
2. 修饰类方法(包含getter/setter方法)修饰器函数有三个实参:
3. 修饰对象的方法(包含getter/setter方法)修饰器函数有三个实参:
4. 修饰类静态方法
5. 在修饰器函数里可以通过实参的个数判断当前decorator作用于类还是方法上。
注意:
Object.defineProperty
方法;SyntaxError: Leading decorators must be attached to a class declaration
4. 可选的修饰器函数返回值(and optionally returns a decorator descriptor to install on the target object)
修饰器函数不仅可以操作类和方法,甚至可以完全创建一个新的类和方法。
TypeError: Property description must be an object
)。@wrap // 完全重定义了 class Person { first = 'John' last = 'Snow' } console.log(Person) ; // { name: 'new Obj' }
// Demo2 function wrapMethod(target, name, decorator) { return { value: true }; } class Person { first = 'John' last = 'Snow' @wrapMethod get fullName() { return
${this.first} ${this.last}
; } } var p = new Person(); console.log(p.fullName); // true输出结果:
三、剥去语法糖外衣
1. 类声明修饰器
ES6表示:
相当于修改了类Foo的定义,在返回Foo变量前先调用了修饰器函数,并优先采用修饰器函数的返回值(真值)作为变量的最终值。
2. 类方法声明修饰器
ES6表示:
其他如多个修饰器,getter/setter方法,对象方法类似。
Issues: 为啥修饰器不能修饰函数
函数存在提升问题,通过上面的desugaring过程我们知道包含修饰器的类或者对象都要被重写转成表达式形式。如果把函数转成表达式就破坏了函数本身提升带来的影响。 假如函数可以声明修饰器,则下面场景存在问题:
转成ES6
小结
装饰器使得被修饰的类或者成员属性被重新定义了。并且在重定义时会调用装饰器函数,提供了操作被修饰类或者属性的机会。
四、修饰器能干什么?
修饰器本质上是语法糖,使用修饰器就可以使用更简洁的代码实现上面罗列的功能。
Issues:
参考