概念
为对象添加新功能
不改变其原有的结构和功能
示例
手机上套一个壳可以保护手机,壳上粘一个指环,可以挂在手指上不容易滑落,这就是一种装饰。手机还是那个手机,手机的功能一点都没变,只是在手机的外面装饰了一些其他附加的功能。日常生活中,这样的例子非常多。
UML类图
代码演示
class Circle {
draw() {
console.log('画一个原型')
}
}
class Decorator {
constructor(circle) {
this.circle = circle
}
draw() {
this.circle.draw()
this.setRedBoder(circle)
}
setRedBoder(circle) {
console.log('设置红色边框')
}
}
// 测试代码
let circle = new Circle()
circle.draw()
let dec = new Decorator(circle) // 装饰
dec.draw()
ES7 装饰器
安装`npm i babel-plugin-transform-decorators-legacy --save-dev`,然后修改`.babrlrc`
{
"presets": ["es2015", "latest"],
"plugins": ["transform-decorators-legacy"]
}
装饰器的原理
@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A;
装饰类
```js
// 一个简单的 demo
@testDec
class Demo {
// ...
}
function testDec(target) {
target.isDec = true;
}
alert(Demo.isDec) // true
```
//可以加参数
```js
// 可以加参数
function testDec(isDec) {
return function(target) {
target.isDec = isDec;
}
}
@testDec(true)
class Demo {
// ...
}
alert(Demo.isDec) // true
```
// mixin 示例
```js
function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list)
}
}
const Foo = {
foo() { alert('foo') }
}
@mixins(Foo)
class MyClass {}
let obj = new MyClass();
obj.foo() // 'foo'
```
装饰方法
// 先看一个 readonly 的 demo
```js
function readonly(target, name, descriptor){
// descriptor 属性描述对象(Object.defineProperty 中会用到),原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
class Person {
constructor() {
this.first = 'A'
this.last = 'B'
}
// 装饰方法
@readonly
name() { return `${this.first} ${this.last}` }
}
var p = new Person()
console.log(p.name())
// p.name = function () {} // 这里会报错,因为 name 是只读属性
```
//再看一个例子,加一个装饰器自动打印日志
```js
function log(target, name, descriptor) {
var oldValue = descriptor.value;
descriptor.value = function() {
console.log(`Calling ${name} with`, arguments);
return oldValue.apply(this, arguments);
};
return descriptor;
}
class Math {
// 装饰方法
@log
add(a, b) {
return a + b;
}
}
const math = new Math();
const result = math.add(2, 4); // 执行 add 时,会自动打印日志,因为有 @log 装饰器
console.log('result', result);
```
core-decorators
[core-decorators.js](https://github.com/jayphelps/core-decorators) 是一个第三方模块,提供了几个常见的修饰器,通过它可以更好地理解修饰器。
用之前肯定得先安装`npm i core-decorators --save`,然后先用它来实现上述的 readonly
```js
// 首先安装 npm i core-decorators --save
// 开始编码:
import { readonly } from 'core-decorators'
class Person {
@readonly
name() {
return 'zhang'
}
}
let p = new Person()
alert(p.name())
// p.name = function () { /*...*/ } // 此处会报错
```
在看一个常用的例子,对已经弃用的协议,给出警告。
```js
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.
```
1