前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • React专栏

    • React组合式开发实战

      • 前端开发的四个时代
      • 企业管理系统的前世今生
      • 可视化页面搭建工具
      • 实战篇 01:开发前准备
      • 实战篇 02:项目脚手架
      • 实战篇 03:页面布局方案
      • 实战篇 04:权限管理机制
      • 实战篇 05:菜单匹配逻辑
      • 实战篇 06:消息通知设计
      • 实战篇 07:多语言支持
      • 继往开来:可视化页面搭建工具
    • React Hooks与Immutable实战

    • React SSR服务端渲染与同构实践

    • IM聊天系统前端开发实践

    • 微前端开发实战

    • React进阶实践

  • Vue专栏

  • 移动端专栏

  • Node专栏

  • 前端工程化专栏

  • 算法专栏

  • Typescript专栏

  • 其他专栏

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

# 高级装饰器

我们上一节了解到了最常用的四种装饰器: 类装饰器、属性装饰器、方法装饰器、访问符装饰器,这已经可以满足我们日常开发的需求了。

但是依然有一些比较高级的用法,这些用法虽然在日常开发中并不多见,但是被大量运用在了基础库层面,要想成为一个名高阶的 TypeScript 开发者还是需要更进一步学习。

# 参数装饰器

参数装饰器,顾名思义是用于修饰参数的装饰器,在 Angular 或者 Nestjs 中都有运用,当然很多基础库也用到了参数装饰器。

function logParameter(target: Object, propertyKey: string, index: number) {
    console.log(target, propertyKey, index);
}

class Person {
    greet(@logParameter message: string,@logParameter name: string): string {
        return `${message} ${name}`;
    }
}
const p = new Person();
p.greet('hello', 'xiaomuzhu');

// Person { greet: [Function] } greet 1
// Person { greet: [Function] } greet 0
@前端进阶之旅: 代码已经复制到剪贴板

我们看到参数装饰器需要三个参数 target、propertyKey、index:

  • target —— 当前对象的原型,也就是说,假设 Person 是当前对象,那么当前对象 target 的原型就是 Person.prototype
  • propertyKey —— 参数的名称,上例中指的就是 greet
  • index —— 参数数组中的位置,比如上例中参数 name 的位置是 1, message 的位置为 0

参数装饰器其实有他的特殊之处,我们之前学到的装饰器是可以修改被修饰者的行为的,比如我们可以把一个方法的「可写性」禁用了,这就实现了类方法的「只读」效果,但是参数装饰器不可以,他没有descriptor参数,因此没有相关的 API 供它修改被修饰者的行为。

那么,这个参数装饰器还有啥用?

参数装饰器可以提供信息,给比如给类原型添加了一个新的属性,属性中包含一系列信息,这些信息就被成为「元数据」,然后我们就可以使用另外一个装饰器来读取「元数据」。

是的,这像极了Java中的注解。

当然我们那种直接修改类原型属性的方法并不优雅,后面我们会介绍有一种更通用更优雅的方式–元数据反射。

# 装饰器工厂

我们先假设这样一个场景,比如我们需要几个装饰器,分别把一个类中的部分属性、类本身、方法、参数的名称打印出来,我们应该怎么做?

大家可能会写出四个不同的装饰器来分别装饰到不同成员上:

@logClass
class Person {

  @logProperty
  public name: string;

  constructor(name : string) {
    this.name = name;
  }

  @logMethod
  public greet(@logParameter message : string) : string {
    return `${this.name} say: ${message}`;
  }
}

// 打印构造函数
function logClass(target: typeof Person) {
    console.log(target)
}

// 打印属性名
function logProperty(target: any, propertyKey: string) {
    console.log(propertyKey);
}

// 打印方法名
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(propertyKey);
}

// 打印参数位置
function logParameter(target: Object, propertyKey: string, index: number) {
    console.log(index);
}

// name
// 0
// greet
// [Function: Person]
@前端进阶之旅: 代码已经复制到剪贴板

确实我们达到效果了,但是装饰器通常是用于抽象和重用,如果一个项目或者库有过量装饰器不仅不能达到上述效果,然而会让项目难以维护.

而且上述装饰器其实是有共同点的,他们都是打印一些关键信息,因此我们可以用一个装饰器工厂来进一步抽象上述代码。

function log(...args : any[]) {
  switch(args.length) {
    case 1:
      return logClass.apply(this, args);
    case 2:
      return logProperty.apply(this, args);
    case 3:
      if(typeof args[2] === "number") {
        return logParameter.apply(this, args);
      }
      return logMethod.apply(this, args);
    default:
      throw new Error("Decorators are not valid here!");
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

我们之后直接用 log 代替 logClass、logProperty、logMethod、logParameter 即可.

装饰器工厂就是一个简单的函数,它返回一种类型的装饰器。

fe

基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • React专栏

    • React组合式开发实战

      • 前端开发的四个时代
      • 企业管理系统的前世今生
      • 可视化页面搭建工具
      • 实战篇 01:开发前准备
      • 实战篇 02:项目脚手架
      • 实战篇 03:页面布局方案
      • 实战篇 04:权限管理机制
      • 实战篇 05:菜单匹配逻辑
      • 实战篇 06:消息通知设计
      • 实战篇 07:多语言支持
      • 继往开来:可视化页面搭建工具
    • React Hooks与Immutable实战

    • React SSR服务端渲染与同构实践

    • IM聊天系统前端开发实践

    • 微前端开发实战

    • React进阶实践

  • Vue专栏

  • 移动端专栏

  • Node专栏

  • 前端工程化专栏

  • 算法专栏

  • Typescript专栏

  • 其他专栏