Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >初探ES7 Decorator

初探ES7 Decorator

作者头像
用户1394570
发布于 2018-08-08 01:58:29
发布于 2018-08-08 01:58:29
43000
代码可运行
举报
文章被收录于专栏:carvencarven
运行总次数:0
代码可运行

装饰器

装饰器是 ES7 新有的特性,它允许我们使用简洁的方式,为已有的类、类的方法、类的属性 添加有趣的修饰。 可使用如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// deco.js
// 假设已实现 装饰器 studentDecorator、readonly、shouldITellYou
@studentDecorator
class Person{

  @readonly
  name = 'carvenzhang';

  @shouldITellYou
  getInfo(){
    //...
  }
}

目前,node 还不支持 decorator,但是,感谢 babel,它提供了转译支持。 我们可以运行使用如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 先安装 babel-cli 及 babel-plugin-transform-decorators-legacy
babel --plugins transform-decorators-legacy deco.js > deco.es5.js && node deco.es5.js

实现 Decorator

那么,装饰器要怎么实现了,什么场景下需要用到decorator呢。 装饰器比较使用于,在完整的系统功能上,提供辅助能力。比如 记录日志查询权限。 目前由一个很好的集成装饰器,可以提供学习:core-decorators

我们可以通过编写一个权限审核的Decorator,达到学习decorator的目的。

编写一个原始类

我们编写一个很简单的class,模拟一些操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// deco.js
class DBAct{
  constructor(options){
    this._options = Object.assign({
      auths:[]
    }, options);
  }
  add(){
    console.log('db add');
  }
  delete(){
    console.log('db delete');
  }
  update(){
    console.log('db update');
  }
  select(){
    console.log('db select');
  }
}

这是一个数据库操作集合,可以通过调用方法, 实现增删改查。

我们通过编写decorator,为其提供操作数据库前的权限审核能力。

实现方法型decorator

首先,我们实现一个 decoraotr,为每个方法提供一个权限检查的能力。 供给方法使用的 decorator 有三个参数,targetnamedescriptor,与Object.defineProperty()的参数一一对应。

target: 类的原型对象,比如 DBAct.prototype name: 要修饰的方法的属性名,比如 add descriptor: 该属性的描述对象,包含 {configurable, enumerable, value, writable } 等值,其中value即实际修饰的函数。

实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function authMethodDecorator(auth){
  //函数封装层,返回decorator
  return function(target, name, descriptor){
    // 获取原函数
    const method = descriptor.value;
    // 重写函数
    descriptor.value = function(...args) {
      // 判断是否有该权限
      if(this._options.auths.includes(auth)){
        // 继续调用原函数
        return method.apply(this, args);
      } else {
        // 无权限
        console.log(`no permission to exec ${name}`)
      }
    }
    return descriptor;
  }
}

整合起来调用如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// deco.js
class DBAct{
  constructor(options){
    this._options = Object.assign({
      auth:{}
    }, options);
  }

  // 只有在有 add 权限的情况下,才能进行 add 操作。
  @authMethodDecorator('add')
  add(){
    console.log('db add');
  }

  // 只有在有 delete 权限的情况下,才能进行 delete 操作。
  @authMethodDecorator('delete')
  delete(){
    console.log('db delete');
  }
  update(){
    console.log('db update');
  }
  select(){
    console.log('db select');
  }
}

// 实例化
const user1 = new DBAct({
  auths:['add'] // user1 仅有 add 权限
});
r1.add();
r1.delete();

// 关于方法的decorator
function authMethodDecorator(auth){
  //..
}

最终通过babel转译,node调用,得到以下结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# exec
babel --plugins transform-decorators-legacy deco.js > deco.es5.js && node deco.es5.js

# echo
db add
no permission to exec delete

实现类的Decorator

我们也可以实现一个Decorator,为整个class的每一个方法都统一做权限检查。 类的decorator仅有一个参数:

target: 调用的类本身,比如 DBAct

实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function authClassDecorator(auth){
   //函数封装层,返回decorator
  return function(target){
    // 获取 class 上所有的描述对象
    const descs = Object.getOwnPropertyDescriptors(target.prototype);
    // 获取 class 上所有的属性名,此方法不兼容 Symbol,实际解决方案参考 core-decorator
    const keys = Object.keys(descs);
    //循环处理每一个方法
    for (let i = 0, l = keys.length; i < l; i++) {
      const name = keys[i];
      const desc = descs[name];

      // 不处理 非函数 和 构造函数
      if (typeof desc.value !== 'function' || name === 'constructor') {
        continue;
      }
      // 为每个方法分别调用一次 authMethodDecorator,重写给 target.prototype
      Object.defineProperty(target.prototype, name, authMethodDecorator(auth)(target.prototype, name, desc));
    }
  }
}

整合起来调用如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// deco.js
//所有方法都需要connect权限才能执行
@authClassDecorator('connect')
class DBAct{
  constructor(options){
    this._options = Object.assign({
      auth:{}
    }, options);
  }
  add(){
    console.log('db add');
  }
  delete(){
    console.log('db delete');
  }
  update(){
    console.log('db update');
  }
  select(){
    console.log('db select');
  }
}

// 实例化
const user1 = new DBAct({
  auths:['add'] // user1 仅有 add 权限
});
r1.add();
r1.delete();

// 关于方法的decorator
function authMethodDecorator(auth){
  //..
}
// 关于类的decorator
function authClassDecorator(auth){
  //..
}

最终通过babel转译,node调用,得到以下结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# exec
babel --plugins transform-decorators-legacy deco.js > deco.es5.js && node deco.es5.js

# echo
no permission to exec add
no permission to exec delete

decorator整合

那么,我们能不能实现一个decoraotor,既能给calss用,也能给method用呢? 可以的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@authDecorator('connect')
class DBAct{
  constructor(options){
    this._options = Object.assign({
      auths:[]
    }, options);
  }

  @authDecorator('add')
  add(){
    console.log('db add');
  }

  @authDecorator('delete')
  delete(){
    console.log('db delete');
  }
  update(){
    console.log('db update');
  }
  select(){
    console.log('db select');
  }
}

const user1 = new DBAct({
  auths:['add', 'connect'] // user1 仅有 add 权限
});
user1.add();
user1.delete();


function authMethodDecorator(auth, target, name, descriptor){
  // 获取原函数
  const method = descriptor.value;
  // 重写函数
  descriptor.value = function(...args) {
    // 判断是否有该权限
    // if(this === target){
    //   return method.apply(target, args)
    // }
    if(this._options.auths.includes(auth)){
      // 继续调用原函数
      return method.apply(this, args);
    } else {
      // 无权限
      console.log(`no permission to exec ${name}`)
    }
  }
  return descriptor;
}

function authClassDecorator(auth, target){
  // 获取 class 上所有的描述对象
  const descs = Object.getOwnPropertyDescriptors(target.prototype);
  // 获取 class 上所有的属性名,此方法不兼容 Symbol,实际解决方案参考 core-decorator
  const keys = Object.keys(descs);
  //循环处理每一个方法
  for (let i = 0, l = keys.length; i < l; i++) {
    const name = keys[i];
    const desc = descs[name];

    // 不处理 非函数 和 构造函数
    if (typeof desc.value !== 'function' || name === 'constructor') {
      continue;
    }
    // 为每个方法分别调用一次 authMethodDecorator,重写给 target.prototype
    Object.defineProperty(target.prototype, name, authMethodDecorator(auth, target.prototype, name, desc));
  }
}

// 通过参数个数判断是 调用方式 method 还是 class
function authDecorator(auth){
  return function handle(...args) {
    if (args.length === 1) {
      return authClassDecorator(auth, ...args);
    }
    return authMethodDecorator(auth, ...args);
  };
}

最终通过babel转译,node调用,得到以下结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# exec
babel --plugins transform-decorators-legacy deco.js > deco.es5.js && node deco.es5.js

# echo
db add
no permission to exec delete

这样,一个通用的decorator就出来了。

迁移

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=jwpzso9zymr

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
干货 | ES6 系列之我们来聊聊装饰器
       点击上方“腾讯NEXT学院”关注我们 Decorator 装饰器主要用于: 1. 装饰类 2. 装饰方法或属性 1 .装饰类 @annotationclass MyClass { } function annotation(target) { target.annotated = true;} 2. 装饰方法或属性 class MyClass { @readonly method() { }} function readonly(targe
腾讯NEXT学位
2020/02/11
6300
干货 | ES6 系列之我们来聊聊装饰器
Decorator 装饰器
Angular大量使用了JS的装饰器特性,先看 ruanyifeng的介绍 使用babel转换 步骤 : npm install -g babel-cli npm init; npm install --save-dev babel-plugin-transform-decorators-legacy babel --plugins transform-decorators-legacy 1.js > 1.es5.js 例1 @eat class Person { constructor() {} }
mafeifan
2018/12/25
4240
设计模式(11)[JS版]-JavaScript中的注解之装饰器模式
装饰器模式模式动态地扩展了(装饰)一个对象的行为,同时又不改变其结构。在运行时添加新的行为的能力是由一个装饰器对象来完成的,它 "包裹 "了原始对象,用来提供额外的功能。多个装饰器可以添加或覆盖原始对象的功能。装饰器模式属于结构型模式。和适配器模式不同的是,适配器模式是原有的对象不能用了,而装饰器模式是原来的对象还能用,在不改变原有对象结构和功能的前提下,为对象添加新功能。
AlbertYang
2020/09/08
8670
设计模式(11)[JS版]-JavaScript中的注解之装饰器模式
decorator 学习小结
decorator 学习小结 1. decorator 是什么 decorator 是装饰者,是 ES7 的语法。 decorator 本质是一个 wrapper,可以动态增强【类】,【实例方法】的能
IMWeb前端团队
2017/12/29
6650
decorator 学习小结
JS 完美的 AOP 编程
看到 decorator这个词的时候,让我回想起了python中的decorator.而,当我看到 decorator中的 @的时候, 我tm确定,这尼玛不就是python吗? 但, too young too naive. es6中的decorator和python很相似,但却又非常的不一样.因为,在js中,decorator是不能用来装饰函数的.(因为有函数提升) so, decorator在js中是用来干嘛的呢? 神马是decorator decorator是以一种近乎trick的方式,让你写更少的代
villainhr
2018/07/03
9420
Decorator 从原理到实践
ES6 已经不必在过多介绍,在 ES6 之前,装饰器可能并没有那么重要,因为你只需要加一层 wrapper 就好了,但是现在,由于语法糖 class 的出现,当我们想要去在多个类之间共享或者扩展一些方法的时候,代码会变得错综复杂,难以维护,而这,也正式我们 Decorator 的用武之地。
Nealyang
2019/09/29
5370
Decorator 从原理到实践
2020的最后一天,不妨了解下装饰器
举一个非常常见的需求。假设我们有一个类Network,它有一个异步getList方法
ACK
2021/01/05
1K0
Decorator 装饰器
大家在前端开发过程中有遇到过 @ + 方法名 这种写法吗?当我第一次看到的时候,直接懵了,这是什么东东……
政采云前端团队
2022/03/29
4130
Decorator 装饰器
一文读懂 @Decorator 装饰器——理解 VS Code 源码的基础
作者:easonruan,腾讯 CSIG 前端开发工程师 1. 装饰器的样子 我们先来看看 Decorator 装饰器长什么样子,大家可能没在项目中用过 Decorator 装饰器,但多多少少会看过下面装饰器的写法: /* Nest.Js cats.controller.ts */ import { Controller, Get } from '@nestjs/common'; @Controller('cats') export class CatsController {   @Get()  
腾讯技术工程官方号
2021/08/09
1.2K0
搭建node服务(四):Decorator装饰器
Decorator(装饰器)是ECMAScript中一种与class相关的语法,用于给对象在运行期间动态的增加功能。Node.js还不支持Decorator,可以使用Babel进行转换,也可以在TypeScript中使用Decorator。本示例则是基于TypeScript来介绍如何在node服务中使用Decorator。
宜信技术学院
2020/11/05
1.7K0
如何用 Decorator 装饰你的 Typescript?
正在着手写 THE LAST TIME 系列的 Typescript 篇,而Decorator 一直是我个人看来一个非常不错的切面方案。所谓的切面方案就是我们常说的切面编程 AOP。一种编程思想,简单直白的解释就是,一种在运行时,动态的将代码切入到类的指定方法、指定位置上的编程思想就是 AOP。AOP 和我们熟悉的 OOP 一样,只是一个编程范式,AOP 没有说什么规定要使用什么代码协议,必须要用什么方式去实现,这只是一个范式。而 Decorator 也就是AOP 的一种形式。
Nealyang
2019/12/30
1.2K0
在JavaScript中使用装饰器
Decorator装饰器是ES7的时候提案的特性,目前处于Stage 3候选阶段(2022年10月)。
luciozhang
2023/04/22
5430
在JavaScript中使用装饰器
Vue中使用装饰器,我是认真的
作为一个曾经的Java coder, 当我第一次看到js里面的装饰器(Decorator)的时候,就马上想到了Java中的注解,当然在实际原理和功能上面,Java的注解和js的装饰器还是有很大差别的。本文题目是Vue中使用装饰器,我是认真的,但本文将从装饰器的概念开发聊起,一起来看看吧。
前端进击者
2021/07/27
1.2K0
TS 设计模式05 - 装饰者模式
在 oop 中,继承是实现多态最简单的方案。同一类的对象会有不同表现时,我们基于此基类去写派生类即可。但有时候,过度使用继承会导致程序无法维护。比如说,人有一个展示自己外观的方法,穿上不同的衣服这个展现形式就不一样。一个人可以选择穿 T-shirt,裤子,裙子,外套等等,它的顺序和搭配是不固定的,如果使用继承,我们对每种组合都需要去定义一个类,比如穿裤子的人,穿裙子的人,穿裤子和裙子的人,先穿裤子再穿外套的人......这样会是我们的程序变得非常庞大而难以维护。 事实上,不管穿什么衣服,本质上仍然是人,衣服只是基于人类的装饰而已。装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
love丁酥酥
2020/09/01
1.3K0
TS 设计模式05 - 装饰者模式
JavaScript设计模式之装饰器模式
手机壳就是装饰器,没有它手机也能正常使用,原有的功能不变,手机壳可以减轻手机滑落的损耗。
FinGet
2019/06/28
4660
JS 装饰器解析
随着 ES6 和 TypeScript 中类的引入,在某些场景需要在不改变原有类和类属性的基础上扩展些功能,这也是装饰器出现的原因。 装饰器简介 作为一种可以动态增删功能模块的模式(比如 redux 的中间件机制),装饰器同样具有很强的动态灵活性,只需在类或类属性之前加上 @方法名 就完成了相应的类或类方法功能的变化。 不过装饰器模式仍处于第 2 阶段提案中,使用它之前需要使用 babel 模块 transform-decorators-legacy 编译成 ES5 或 ES6。 在 TypeScrip
牧云云
2018/04/28
2.9K0
JS 装饰器解析
TS 进阶 - 实际应用 03
装饰器的本质是一个函数,只不过它的入参时提前确定好的。TypeScript 中的装饰器目前只能在类及类成员上使用。
Cellinlab
2023/05/17
4940
一文读懂 JS 装饰器,这是一个会打扮的装饰器
装饰器是最新的 ECMA 中的一个提案,是一种与类(class)相关的语法,用来注释或修改类和类方法。装饰器在 Python 和 Java 等语言中也被大量使用。装饰器是实现 AOP(面向切面)编程的一种重要方式。
用户1462769
2020/03/30
1.3K0
一文读懂 JS 装饰器,这是一个会打扮的装饰器
玩转ES6(四)Set、Map、Class类和decorator 装饰器
在看Class之前建议看一下js的面向对象 https://juejin.im/post/5b8a8724f265da435450c591
前端迷
2019/12/03
8270
大型前端如何分析用户行为和追踪函数调用链
在很多时候我们项目越来越大的时候,我们希望去监听局部某些类方法的性能,这个时候我们既不想影响源代码的功能,但又想借助某些方案去窥探类方法内部的运行效能,此时我们就可以考虑使用装饰器对类方法性能进行监听。装饰器相信大家都不陌生了,虽然在 Javasript 里面它仍处于提议阶段,但是我们已经可以 TypeScript 里面运用这个特性,也可以借助 babel 的语法转换在 Javasript 里面使用。
wscats
2020/06/18
2K0
大型前端如何分析用户行为和追踪函数调用链
相关推荐
干货 | ES6 系列之我们来聊聊装饰器
更多 >
LV.0
这个人很懒,什么都没有留下~
加入讨论
的问答专区 >
    领券
    社区富文本编辑器全新改版!诚邀体验~
    全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
    查看详情【社区公告】 技术创作特训营有奖征文