ES6的decorator相信大家都听说过,但是用的可能会比较少,今天就一起来看一下这个decorator是干嘛的
装饰器(decorator)是一种与类相关的语法,用来注释或修改类和类的方法
装饰器是一种函数,使用@+函数名
的写法,它可以放在类和类方法的定义前面
1 类的装饰器
装饰器可以用来修饰整个类
@testable
class MyTestableClass {
// ...
}
function testable(target) {
target.isTestable = true;
}
MyTestableClass.isTestable // true
上面的代码中,@testable
是一个装饰器,修饰了MyTestableClass
这个类,testable
是一个函数,具体实现是如何修饰这个类的,修饰的内容是给类增加了isTestable
这个**静态属性
**
装饰器的行为如下:
@decorator
class A {}
A = decorator(A) || A
也就是说,装饰器是一个对类进行处理的函数,这个函数可以传参,也可以被多层封装,外层的参数为传递的参数,最内层的参数为修饰的类对象
function testable(isTestable) {
return function(target) {
target.isTestable = isTestable
}
}
@testable(true)
class MyTestClass {
}
MyTestClass.isTestable // true
装饰器是在编译阶段就会执行的
上面代码是为类添加静态属性,下面的代码则是为一个类添加实例属性
function testable(target) {
target.prototype.isTestable = true
}
@testable
class MyTestClass {
}
let mt = new MyTestable
mt.isTestable //true
现在有一个场景,需要将一个对象的方法添加到一个类里,传统的方法,使用Object.assign
const Foo = {
foo() {
console.log('foo')
}
}
class MyClass {}
Object.assign(MyClass.prototype, Foo)
现在有了装饰器,我们也可以这么写
function testable(obj) {
return function (target) {
Object.assign(target.prototype, obj)
}
}
@testable(Foo)
MyClass{}
let obj = new MyClass
obj.foo() // 'foo'
2 方法的装饰
修饰一个方法例子:
class Person {
@nonconfig
kidCount() { return 12 }
}
function nonconfig(target, name, descriptor) {
descriptor.configurable = false;
return descriptor;
}
console.log(Object.getOwnPropertyDescriptor(Person.prototype, 'kidCount'))
再看下面一个例子,可以打印日志
class Math {
@log
add(a, b) {
return a + b
}
}
function log (target, name, descirptor) {
var oldValue = descirptor.value
descirptor.value = function() {
console.log(`Calling ${name} with ` , arguments)
return oldValue.apply(this, arguments)
}
return descirptor
}
const math = new Math
math.add(1, 2) // Calling add with Arguments(2)
3 core-decorators.js
core-decorators.js
是一个第三方的模块,提供了常见的装饰器,可以直接使用
1、autobind
使得方法中的this对象,绑定原始对象
import { autobind } from 'core-decorators';
class Person {
@autobind
getPerson() {
return this;
}
}
let person = new Person();
let getPerson = person.getPerson;
getPerson() === person;
// true
上面代码中如果不加@autobind
,则getPerson返回一个undefined
,原因是环境处于严格模式,非严格模式应该是window
2、readonly,修饰类里的属性,为只读模式
import { readonly } from 'core-decorators'
class Meal {
@readonly
entree = 'steak'
}
let m = new Meal
m.entree = 'salmon'
// Uncaught TypeError: Cannot assign to read only property 'entree' of object
3、override
检查子类的方法,是否覆盖父类的方法
import { override } from 'core-decorators'
class Parent {
speak (first, last) {}
}
class Child extends Parent {
@override
speak() {} //Uncaught SyntaxError: Child#speak() does not properly override Parent#speak(first, last)
}
上面代码中,子类的方法缺少两个参数
4、deprecate显示一条警告,表示该方法将废除
import { deprecate } from 'core-decorators';
class Person {
@deprecate
facepalm() {}
@deprecate('We stopped facepalming')
facepalmHard() {}
@deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' })
facepalmHarder() {}
}
let person = new Person();
person.facepalm();
// DEPRECATION Person#facepalm: This function will be removed in future versions.
person.facepalmHard();
// DEPRECATION Person#facepalmHard: We stopped facepalming
person.facepalmHarder();
// DEPRECATION Person#facepalmHarder: We stopped facepalming
//
// See http://knowyourmeme.com/memes/facepalm for more details.
//