这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战
背景
学习前端三个月了,准备刷刷面试题,总结总结,一天几道面试题,向大厂进军。
什么是Decorator
Decorator 也叫装饰器,是一种与class 相关的语法。重要的事情说三遍:与class相关。
装饰器字面意思就是装饰的作用,在程序中也是装饰,主要用来增强原有的类或者原有类方法的功能。
装饰器是一个函数,通用调用方式 @+函数名。它可以放在类或者类方法的定义前面,可以接受参数。
类装饰器
当对类本身进行装饰的时候,能够接受一个参数,即类本身。
我们看一下简单代码:
//装饰器
function testClassDecorator(target) {
target.isTest = true;
}
//测试类
@testClassDecorator
class Test {
private name = '';
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
//导出测试类
export default Test;
import Test from '@/es6Test/classTest';
const a = new Test('张三');
console.log('测试实例对象==', a.isTest, '==类对象==', Test.isTest);
输出结果: 测试实例对象== undefined ==类对象= true
上面代码中@testClassDecorator 就是一个装饰器。它修改的是类本身。它为Test类加上了静态属性isTest。testClassDecorator函数中的target就是Test类本身。
相当于:
//装饰器
function testClassDecorator(target) {
target.isTest = true;
}
//测试类
@testClassDecorator
class Test { }
Test = testClassDecorator(Test) || Test;
就是对一个类进行函数处理,函数的第一个参数是类本身。
注意: 装饰器是对类的行为改变,是代码编译的时候就发生改变了,不是在运行时。
装饰器接受参数
很简单,就是在装饰器函数外面再包装一层函数。
//接受参数
function testClassDecorator(age) {
return function (target) {
target.age = age;
};
}
@testClassDecorator(15)
class Test {
private name = '';
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
export default Test;
给实例对象增加属性
其实就是操作target.prototype
function testClassDecorator(age) {
return function (target) {
target.prototype.age = age;
};
}
@testClassDecorator(15)
class Test {
private name = '';
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
export default Test;
import Test from '@/es6Test/classTest';
const a = new Test('张三');
console.log('测试实例对象==', a.age, '==类对象==', Test.age);
输出结果:
测试实例对象== 15 ==类对象= undefined
给实例对象增加方法
//装饰器
function testClassDecorator(...list) {
//给实例增加方法
return function (target) {
Object.assign(target.prototype, ...list);
};
}
const Foo = {
foo(num) {
console.log('foo==', num);
},
};
@testClassDecorator(Foo)
class Test {
private name = '';
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
export default Test;
import Test from '@/es6Test/classTest';
const a = new Test('张三');
//调用增强的方法
a.foo();
输出结果: foo== 2
React中具体应用
- 由于要经常使用react-redux,我们修改connect的写法为装饰器写法,使代码更优雅:
2. 我们经常使用ReactContext,经常需要写 Consumer。我们也可以把这个改为装饰器写法
类方法装饰器
装饰器不仅可以修饰类,还可以是修饰类的属性。
那修饰类方法的装饰器与修饰类的装饰器有什么区别呢??
我们先来看一个简单的案例:
//方法装饰器
function testClassDecorator(target, name, descriptor) {
descriptor.writable = false;
return descriptor;
}
class Test {
private name = '';
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
@testClassDecorator
setName(name) {
this.name = name;
}
}
export default Test;
装饰器第一个参数是类的原型对象,上例是Test.prototype,装饰器的本意是要“装饰”类的实例,但是这个时候实例还没生成,所以只能去装饰原型(这不同于类的装饰,那种情况时target参数指的是类本身);第二个参数是所要装饰的属性名,第三个参数是该属性的描述对象。
带参数的类方法装饰器:
//方法装饰器带参数
function testClassDecorator(age) {
return function(target, name, descriptor){
descriptor.writable = false;
return descriptor;
}
}
执行顺序
如果一个类或者方法有多个装饰器,顺序是先从外到内,然后执行从内到外
结语
一步一步慢慢来,踏踏实实把活干!