ES7 装饰器

阅读能解决问题-:
1)装饰器有什么用,主要功能?
2)装饰器?减少引入,减少代码,可以扩展,不需要改原有方法的代码位置
3)放置位置,可以是类、类成员(方法/属性)
4)执行顺序
5)目前项目代码可以加装饰器吗?
6)是不是一定要用类

目录:
1、前言
2、ES7 装饰器
3、应用
4、装饰器只能用于类上吗?为什么不能用于函数?—因为存在函数提升,类不会
5、第三方 core-decorators.js,提供一下装饰器
6、已有项目添加装饰器

1、前言

装饰器是 ES7 中的一个提案,是一种与类(class)相关的语法,用来注释或修改类和类方法。装饰器在 Python 和 Java 等语言中也被大量使用。装饰器是实现 AOP(面向切面)编程的一种重要方式。
装饰器类:

@frozen
class Foo {
@configurable(false)
method() {}}

@frozen 和 @configurable 就是我们说的装饰器。
可以看出是通过@来使用装饰器。一共用了两种:一个用在类上,一个用在方法上。
装饰器属性:这个 @readonly 可以将 count 属性设置为只读。可以看出来,装饰器大大提高了代码的简洁性和可读性。
class Person {
@readonly count = 0;
}

2、ES7 装饰器

2.1 python中的装饰器

def auth(func):def inner(request,*args,**kwargs):v = request.COOKIES.get('user')if not v:return redirect('/login')return func(request, *args,**kwargs)return inner@auth
def index(request):v = request.COOKIES.get("user")return render(request,"index.html",{"current_user":v})

这个 auth 装饰器是通过检查 cookie 来判断用户是否登录的。auth 函数是一个高阶函数,它接收了一个 func 函数作为参数,返回了一个新的 inner 函数。
在 inner 函数中进行 cookie 的检查,由此来判断是跳回登录页面还是继续执行 func 函数。
在所有需要权限验证的函数上,都可以使用这个 auth 装饰器,很简洁明了且无侵入。

2.2 javascript装饰器

JavaScript 中的装饰器和 Python 的装饰器类似,依赖于 Object.defineProperty,一般是用来装饰类、类属性、类方法。
使用装饰器可以做到不直接修改代码,就实现某些功能,做到真正的面向切面编程。这在一定程度上和 Proxy 很相似,但使用起来比 Proxy 会更加简洁。

2.3 类装饰器-接受一个目标类作为参数

1)添加静态属性

const decoratorClass = (targetClass) => {targetClass.test = '123'
}
@decoratorClass
class Test {}
Test.test; // '123'

2)修改原型,给实例添加新属性

const withSpeak = (targetClass) => {const prototype = targetClass.prototype;prototype.speak = function() {console.log('I can speak ', this.language);}
}
@withSpeak
class Student {constructor(language) {this.language = language;}
}
const student1 = new Student('Chinese');
const student2 = new Student('English');
student1.speak(); // I can speak  Chinesestudent2.speak(); // I can speak  Chinese

3)利用高阶函数的属性,给装饰器传参,通过参数来判断对类进行什么处理。

const withLanguage = (language) => (targetClass) => {targetClass.prototype.language = language;
}
@withLanguage('Chinese')
class Student {
}
const student = new Student();
student.language; // 'Chinese'

4)react-redux中,需要将store数据映射到组件中,connect 是一个高阶组件,它接收了两个函数

mapStateToProps 和 mapDispatchToProps 以及一个组件 App,最终返回了一个增强版的组件。
class App extends React.Component {
}
connect(mapStateToProps, mapDispatchToProps)(App)
使用装饰器写法:
@connect(mapStateToProps, mapDispatchToProps)
class App extends React.Component {
}

2.4 类属性装饰器

类属性装饰器可以用在类的属性、方法、get/set 函数中,一般会接收三个参数:

  1. target:被修饰的类
  2. name:类成员的名字
  3. descriptor:属性描述符,对象会将这个参数传给 Object.defineProperty
    使用类属性装饰器可以做到很多有意思的事情,比如 readonly 的例子:
function readonly(target, name, descriptor) {descriptor.writable = false;return descriptor;
}
class Person {@readonly name = 'person'
}
const person = new Person();
person.name = 'tom'; 
// 还可以用来统计一个函数的执行时间,以便于后期做一些性能优化。
function time(target, name, descriptor) {const func = descriptor.value;if (typeof func === 'function') {descriptor.value = function(...args) {console.time();const results = func.apply(this, args);console.timeEnd();return results;}}
}
class Person {@timesay() {console.log('hello')}
}
const person = new Person();
person.say();

2.5 装饰器组合

如果想要多个装饰器,可以叠加使用

class Person {@time@logsay() {}
}

在这里插入图片描述

3、应用

1)基本使用:

给一个类添加log或console,但如果这个方法所有类都要加,那得一个一个写,很麻烦。这时候可以用装饰器去拓展每一个class:

function addConcole(target) {// 拓展原型方法target.prototype.log = function(msg) {console.log(`[${new Date()} ${msg}`);};// 拓展静态属性target.myName = '一个类'return target;
}
@addConcole
class MyClass {constructor() {}
}const myObj = new MyClass();
myObj.log('林三心');
// [Sat Jul 08 2023 17:31:55 GMT+0800 (中国标准时间) 林三心
console.log(MyClass.myName)
// 一个类

拓展原型方法,拓展静态属性

2)Node路由请求Url(类成员装饰器)

在使用一些 Node 的框架时,在写接口的时候,我们可能会经常看到这样的代码

  • 当我们请求路径是 GET doc 时会匹配到findDocById
  • 当我们请求路径是 POST doc 时会匹配到createDoc
class Doc {@Get('doc')async findDocById(id) {}@Post('doc')async createDoc(data) {}
}

其实这个 @Get 和 @Post ,是框架提供给我们的 类成员装饰器,是的,类成员也能使用装饰器,类成员装饰器接收三个参数:

  • target 是目标类的原型对象
  • key 表示目标类成员的键名
  • descriptor 是一个属性描述符对象,它包含目标类成员的属性特性(例如 value、writable 等)
function Get(path) {return function(target, key, descriptor) {console.log({target,key,descriptor})}
}

在这里插入图片描述

3)接口权限控制(类成员装饰器叠加)

  • GET doc 接口只能 管理员 才能访问
  • POST doc 接口只能 超级管理员 才能访问
function authenticated(target, key, descriptor) {const originalMethod = descriptor.value;descriptor.value = function(...args) {if (isAuthenticated()) {originalMethod.apply(this, args);} else {console.log('Unauthorized access!');}};return descriptor;
}
class Doc {@Get('doc')@authenticated('admin')async findDocById(id) {}@Post('doc')@authenticated('superAdmin')async createDoc(data) {}
}

多个装饰器叠加执行顺序:从下往上, 离class定义最近的先执行。

4)记录日志的装饰器:

  • 函数调用时间
  • 函数调用参数
// 日志装饰器函数
function logDecorator(target, key, descriptor) {const originalMethod = descriptor.value; // 保存原始方法descriptor.value = function(...args) {console.log(`调用函数:${key}`);console.log(`参数:${JSON.stringify(args)}`);// 执行原始方法const result = originalMethod.apply(this, args);console.log(`返回值:${result}`);return result;};return descriptor;
}// 示例类
class Example {@logDecoratorgreet(name) {return `Hello, ${name}!`;}
}// 测试
const example = new Example();
example.greet('林三心');

5)缓存装饰器

// 缓存装饰器函数
function cacheDecorator(target, key, descriptor) {const cache = {}; // 缓存对象const originalMethod = descriptor.value; // 保存原始方法descriptor.value = function(...args) {const cacheKey = JSON.stringify(args); // 生成缓存键if (cacheKey in cache) {console.log('从缓存中获取结果');return cache[cacheKey]; // 直接返回缓存结果}// 执行原始方法const result = originalMethod.apply(this, args);console.log('将结果缓存起来');cache[cacheKey] = result; // 缓存结果return result;};return descriptor;
}// 示例类
class Example {@cacheDecoratorgetValue(key) {console.log('执行函数逻辑');return key + Math.random(); // 模拟复杂的计算逻辑}
}// 测试
const example = new Example();
console.log(example.getValue('foo'));
console.log(example.getValue('foo')); // 从缓存中获取结果

6)防抖节流

@debounce(500)
submit() {}@throttle(200)
handleScroll() {}

7)错误处理装饰器

跟日志装饰器一样,错误其实也是日志的一部分,错误日志非常重要,因为 Nodejs 的线上报错,大部分都需要通过查日志来进行定位,所以我们也可以封装一个错误的处理装饰器~

function errorHandler(target, key, descriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args) {try {originalMethod.apply(this, args);} catch (error) {console.error(`Error occurred in ${key}:`, error);}};return descriptor;
}
// 使用:
class Common {@log()commonRequest(url, params) {return request(url, params)}
}const common = new Common()
common.commonRequest('http://xxx.com', { name: 'l' })
Error occurred in commonRequest: Request Error

8)计时装饰器

function timing(target, key, descriptor) {const originalMethod = descriptor.value;descriptor.value = function(...args) {const start = performance.now();const result = originalMethod.apply(this, args);const end = performance.now();console.log(`Execution time of ${key}: ${end - start} milliseconds`);return result;};return descriptor;
}class Common {@timing()commonRequest(url, params) {return request(url, params)}
}
const common = new Common()
common.commonRequest()
Execution time of commonRequest: 20 milliseconds

9)参数检验装饰器

在没有ts类型监测的时候,可以用这个:

function validateArgs(...types) {return function (target, key, descriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args) {for (let i = 0; i < types.length; i++) {const type = types[i];const arg = args[i];if (typeof arg !== type) {throw new Error(`Invalid argument type at index ${i}`);}}originalMethod.apply(this, args);};return descriptor;};
}
class Common {@validateArgs(['string', 'object'])commonRequest(url, params) {return request(url, params)}
}
const common = new Common()
common.commonRequest(123, 123) // 报错

4、装饰器只能用于类上吗?为什么不能用于函数?—因为存在函数提升,类不会

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

👆 想在执行函数的时候couter+1,但其实counter等于0,因为函数提升后是这样的:

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

5、第三方 core-decorators.js,提供一下装饰器

@autobind:使得方法中的this对象,绑定原始对象
@readonly:使得属性或方法不可写。
@override:检查子类的方法,是否正确覆盖了父类的同名方法,如果不正确会报错。
@deprecate (别名@deprecated):在控制台显示一条警告,表示该方法将废除。

6、目前已有项目上添加装饰器:

确保项目使用了 Babel 或 TypeScript 这样的工具来编译js 代码,因为装饰器是 ES7 的一个提案,需要转译为 ES5 以在现有浏览器中运行。

1)安装依赖:
对于babel需要添加一下依赖:

npm install --save-dev @babel/plugin-proposal-decorators 
# 或 
yarn add --dev @babel/plugin-proposal-decorators

对于 TypeScript,无需额外安装插件,装饰器已经内置在 TypeScript 中。
2)配置

对于 Babel,在 .babelrc 文件中添加以下配置:
{"plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }]]
}

对于 TypeScript,确保 tsconfig.json 文件中有以下配置:

{"compilerOptions": {"experimentalDecorators": true,"emitDecoratorMetadata": true}
}

参考+其他学习资料:
1、ES7-装饰器Decorator详解 https://zoeice.com/es-decorator/
2、提案地址:JavaScript Decorators。
3、 5分钟带你了解【前端装饰器】,“高大上”的“基础知识” (qq.com)
4、 分享能提高开发效率,提高代码质量的八个前端装饰器函数~ (qq.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/183194.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

24张宇八套卷复盘(五)

张八&#xff08;&#xff09;94选择25填空20高数大题25线代大题12概率大题12 前言 临近考试冲刺阶段&#xff0c;感觉做过的卷子很难再提起精神去复盘&#xff0c;于是在这里进行一下复盘。 主要是对于整体试卷结构的把握&#xff0c;以及考试状态的复盘。 简单的卷子把会做的…

数据库设计,原来找到对的辅助工具这么简单

糟糕的数据库设计后果&#xff1f;随着时间的流逝&#xff0c;需要花更多的时间摆弄数据结构。在处理大型复杂项目时&#xff0c;这变成了一个更大的问题。 合适的数据库设计工具可以帮助我们节省大量时间&#xff0c;同时还会确保不会因使用不当丢失数据&#xff0c;在线数据库…

【RabbitMQ】RabbitMQ 消息的堆积问题 —— 使用惰性队列解决消息的堆积问题

文章目录 一、消息的堆积问题1.1 什么是消息的堆积问题1.2 消息堆积的解决思路 二、惰性队列解决消息堆积问题2.1 惰性队列和普通队列的区别2.2 惰性队列的声明方式2.3 演示惰性队列接收大量消息2.4 惰性队列的优缺点 一、消息的堆积问题 1.1 什么是消息的堆积问题 消息的堆积…

517-0224-16A-458525 531X303MCPARG1 现代工厂中DCS与PLC的比较

517-0224-16A-458525 531X303MCPARG1 现代工厂中DCS与PLC的比较 分布式控制系统(DCSs)和可编程逻辑控制器(PLC)之间的区别可以归结为一个简单的足球比喻。你的指挥系统是你的船长。团队名单上的第一个名字&#xff0c;你的DCS是可靠的&#xff0c;勤奋的&#xff0c;控制着整个…

Android codec2 视频框架 之应用

文章目录 应用流程外部主动获取输入和输出buffer外部设置回调 内部流程 应用流程 外部主动获取输入和输出buffer 解码的调用流程&#xff0c;以android原生的一个bin来说明 android 原生代码位置&#xff1a; frameworks/av/cmds/stagefright/codec.cpp frameworks/av/cmds/st…

Synchronized关键字使用不合理,导致的多线程下线程阻塞问题排查

在为客户进行性能诊断调优时&#xff0c;碰到了一个Synchronized关键字使用不合理导致多线程下线程阻塞的情况。用文字记录下了问题的整个发现-排查-分析-优化过程&#xff0c;排查过程中使用了商业化产品——XLand性能分析平台&#xff0c;通过文章主要希望跟大家分享下分析和…

vue3错误排查-POST请求的body参数 传参方式form-data和json

问题&#xff1a;vue3实现登录功能&#xff0c;登录成功后 跳转到登陆后的界面 一秒后 闪退回登录页 对应的输出结果也一闪而过&#xff0c;反复复查了代码&#xff0c;没问题。 自测&#xff1a;进行断点输出调试。强行跳转到登陆后的界面&#xff0c;查看输出的结果。 没有报…

使用腾讯云轻量服务器安装AList

新人有免费两个月试用轻量服务器&#xff0c;使用云服务器商自带的webshell登录&#xff1b; 我这儿用docker安装Alist&#xff0c;因为服务器没自带docker&#xff0c;所以具体安装docker centos7.0最快速安装docker的方法 通过 Docker 部署 Alist 命令&#xff1a; docke…

“菊风Juphoon”邀您莅临11月22-24日CNF南京应急展消防展 | 展位号:115-1

公司简介 菊风依托互联网和电信网音视频融合技术积累&#xff0c;提供智能化的音视频统一通信产品及服务。面向应急管理、消防救援、智慧城市等多个领域&#xff0c;菊风推出适用于全网通的统一通信一体机、统一通信平台。 此外&#xff0c;菊风还提供视频能力平台&#xff0…

客户案例 | 思腾合力助力深度图灵生成式AI应用平台建设

近年来&#xff0c;娱乐行业发展迅猛&#xff0c;市场容量不断扩大。从娱乐产业发展来看&#xff0c;用户对于娱乐内容和体验的需求不断攀升&#xff0c;如何将生成式AI更好的应用于照片修复、创意摄影、漫画创作、图片生成等场景中是对娱乐行业各科技公司的挑战和考验&#xf…

【面试题01】找出数组中的最长前缀

题目1&#xff1a;如图&#xff0c;finally中的输出语句会执行吗&#xff1f;&#xff08;另外自己去考虑虚拟机退出、catch中抛异常、try中抛异常、守护线程等相关问题&#xff09; 题目2&#xff1a;Byte"hello"报错吗&#xff1f;Byte7报错吗&#xff1f; 不会报…

2023.11.6 Spring 使用注解存储 Bean 对象

目录 前置工作 使用类注解 五大类注解 Controller&#xff08;控制器&#xff09; Service&#xff08;服务&#xff09; Repository&#xff08;仓库&#xff09; Component&#xff08;组件&#xff09; Configuration&#xff08;配置&#xff09; 使用方法注解 B…

531X304IBDASG1 F31X303MCPA002/00 发电用分布式控制系统

531X304IBDASG1 F31X303MCPA002/00 发电用分布式控制系统 2021年4月20日&#xff0c;马萨诸塞州戴德姆。-新的ARC咨询小组关于全球的研究发电用分布式控制系统(DCS)市场显示&#xff0c;全球燃煤发电能力的减少继续阻碍增长。老化的燃煤电厂越来越多地被淘汰&#xff0c;而不是…

在Ubuntu上安装Redis并学习使用get、set和keys命令

目录 安装Redis切换到root用户搜索redis相关软件包安装redis修改配置文件重启服务器使用redis客户端连接服务器 get与set命令keys 安装Redis 我们在Ubuntu20.04上进行Redis的安装 切换到root用户 使用su命令&#xff1a; 在终端中&#xff0c;输入su并按回车键。然后输入roo…

jenkins gitlab CI/CD

jenkins的安装教程就不说了&#xff1a;Jenkins docker 一键发布 (一)_jenkins 一键发布-CSDN博客 最近打算从svn切换到gitlab&#xff0c;所以配置了一下jenkins的git 很简单&#xff0c;直接上图 1 选择 Git 2 录入gitlab的http地址&#xff08;由于我的git地址不是22端口&…

WebSocket Day 01:入门案例

前言 欢迎来到WebSocket入门案例系列的第一天&#xff01;在今天的博客中&#xff0c;我们将一起探索WebSocket的基础知识和使用方法。本系列将以一个简单的入门案例为基础&#xff0c;带领您逐步了解WebSocket的原理和用法。 一、什么是 WebSocket ? WebSocket是一种在Web应…

java版直播商城免费搭建平台规划及常见的营销模式+电商源码+小程序+三级分销+二次开发

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框架…

web —— html

Web —— css基础 1. HTML2. 基本HTML结构3. HTML常用标签3.1 文本相关标签3.2 HTML图像标签3.3 HTML超链接标签3.4 HTML表&#xff0c;单3.4.1 HTML表格3.4.2 HTML表单&#xff0c;输入框&#xff08;多选框&#xff0c;单选框&#xff09;下拉框 3.5 HTML分区标签3.5.1 div标…

【Midjourney入门教程3】写好prompt常用的参数

文章目录 1、图片描述词&#xff08;图片链接&#xff09;文字描述词后缀参数2、权重划分3、后缀参数版本选择&#xff1a;--v版本风格&#xff1a;--style长宽比&#xff1a;--ar多样性: --c二次元化&#xff1a;--niji排除内容&#xff1a;--no--stylize--seed--tile、--q 4、…

实战-edusrc漏洞挖掘

0x01系统初探 通过fofa对大学进行搜索 fofa:host"edu.cn" &amp;&amp; status_code"200"在随意的翻阅查看时&#xff0c;发现访问xxx.edu.cn登录页面会优先访问登录后的页面&#xff0c;再跳转至登录页面。盲猜应该是前端校验&#xff0c;可以通过…