decorate

一、定义

装饰器是一种函数,写成@ + 函数名。它可以放在类和类方法的定义前面

1
2
3
4
5
6
@frozen
class Foo {
@configurable(false)
method() {}
expensiveMethod() {}
}

装饰器只能用于类和类的方法,不能用于函数,因为存在函数提升

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var counter = 0;
var add = function () {
counter++;
};
@add
function foo() {
}

// 函数提升实际等同于下面

var counter;
var add;
@add
function foo() {
}
counter = 0;
add = function () {
counter++;
};

如果一定要装饰函数,可以采用高阶函数的形式直接执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function doSomething(name) {
console.log('Hello, ' + name);
}

function loggingDecorator(wrapped) {
return function() {
console.log('Starting');
const result = wrapped.apply(this, arguments);
console.log('Finished');
return result;
}
}

const wrapped = loggingDecorator(doSomething);

二、装饰器使用

testable函数的参数target是MyTestableClass类本身

1
2
3
4
5
6
7
8
9
@testable
class MyTestableClass {
}

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

console.log(MyTestableClass.isTestable) // true

三、封装多参数

1
2
3
4
5
6
7
8
function testable(isTestable) {
return function(target) {
target.isTestable = isTestable;
}
}
@testable(true)
class MyTestableClass {}
console.log(MyTestableClass.isTestable) // true

四、添加实例属性

如果想添加实例属性,可以通过目标类的prototype对象操作

1
2
3
4
5
6
7
8
9
10
function testable(target) {
target.prototype.isTestable = true;
}

@testable
class MyTestableClass {}

let obj = new MyTestableClass();

obj.isTestable // true

五、 react中使用

1
2
3
4
5
6
7
class MyReactComponent extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);

装饰器

@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}

六、方法的装饰器

  • 装饰器第一个参数是类的原型对象,Person.prototype

  • 第二个参数是所要装饰的属性名

  • 第三个参数是该属性的描述对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}

function readonly(target, name, descriptor){
// descriptor对象原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}

七、 mixin 混入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list);
};
}

import { mixins } from './mixins';

const Foo = {
foo() { console.log('foo') }
};

@mixins(Foo)
class MyClass {}

let obj = new MyClass();
obj.foo() // "foo"
返回
顶部