【大前端】js装饰器的10年难产之路

  js装饰器最初是在ECMAScript2015(ES6)规范中提出的一个Stage 1的提案,为了应对不断增加的元编程功能的需求,希望能够更方便地操作类和对象的行为,同时减少重复代码和简化复杂功能的实现。

装饰器是一种结构设计模式,通过将对象置于包含行为的特殊包装器对象中,可以将新的行为附加到对象上。

  从2015年的首次提出至今近10年依然处于Stage 3阶段,依然还没有成为规范的一部分,那么js装饰器这10年间到底经历了什么变迁!

以下内容翻译自 ECMAScript Decorators. The Ones That are Real

原文作者:Vladyslav Zubko

2014年4月 - 阶段0

  装饰器是由Yehuda Katz提出的,最初打算成为ECMAScript2016(ES7)的一部分。

type Decorator = (
  target: DecoratedClass,
  propertyKey: string,
  descriptor: PropertyDescriptor
) => PropertyDescriptor | void

function debounce(delay: number): PropertyDescriptor {
  return (target, propertyKey, descriptor) => {
    let lastTimeout: number
    const method = descriptor.value

    descriptor.value = (...args: unknown[]) => {
      clearInterval(lastTimeout)

      lastTimeout = setTimeout(() => method.call(null, ...args), delay)
    }

    return descriptor
  }
}

  在这个阶段,你已经可以看到装饰器API为什么会在后来经历如此重大的变化之一。装饰器的第一个参数是整个类,即使你只是装饰其中的一个成员。此外,它假定开发人员可以改变这个类。JavaScript引擎总是努力尽可能地进行优化,在这种情况下,开发人员对整个类的改变削弱了引擎提供的大量优化。后来,我们会看到,这确实是装饰器API多次重写的一个重要原因,几乎是从头开始。

2015-03 – 阶段1

  在没有重大变化的情况下,该提案进入了第二阶段。然而,发生了一件显著影响该提案进一步发展的事件:TypeScript1.5发布了,它支持装饰器。尽管装饰器被标记为实验性的(–experimentalDecorators),像Angular和MobX这样的项目开始积极地使用它们。此外,这些项目的整体工作流程假定专门使用装饰器。由于这些项目的流行,许多开发人员错误地认为装饰器已经成为官方JS标准的一部分。

  这为TC39委员会带来了额外的挑战,因为他们不得不考虑开发者社区的期望和要求以及语言引擎中的优化问题。

2016-07 – 阶段2

  在装饰器提案达到第二阶段后,其API开始经历重大变化。此外,该提案曾一度被称为“JavaScriptESnext类特性”。在其开发过程中,有许多关于装饰器应该如何结构化的想法。

type Decorator = (args: {
  kind: 'method' | 'property' | 'field',
  key: string | symbol,
  isStatic: boolean,
  descriptor: PropertyDescriptor
}) => {
  kind: 'method' | 'property' | 'field',
  key: string | symbol,
  isStatic: boolean,
  descriptor: PropertyDescriptor,
  extras: unknown[]
}

  在第二阶段结束时,装饰器API的形式如下所示:

type Decorator = (
  value: DecoratedValue,
  context: {
    kind: 'class' | 'method' | 'getter' | 'setter' | 'field' | 'accessor',
    name: string | symbol,
    access?: {
      get?: () => unknown,
      set?: (value: unknown) => void
    },
    private?: boolean,
    static?: boolean,
    addInitializer?: (initializer: () => void) => void
  }
) => UpdatedDecoratedValue | void

function debounce(delay: number): UpdatedDecoratedValue {
  return (value, context) => {
    let lastTimeout = null

    return (...args) => {
      clearInterval(lastTimeout)

      lastTimeout = setTimeout(() => value.call(null, ...args), delay)
    }
  }
}

  第二阶段历时6年,期间装饰器API经历了重大变化。然而,正如我们从上面的代码中可以看到的,变异被排除在外。这使得该提案对于JS引擎以及各种平台、框架和库更加可接受。但装饰器的发展历史并未结束。

2022年3月 - 阶段3

  经过多年的变化和完善,装饰器终于达到了第三阶段。在第二阶段的广泛调整和完善的基础上,第三阶段开始时并没有出现重大变化。一个特别的亮点是创建了一个名为装饰器元数据的新提案。

2022年8月 - SpiderMonkey Newsletter

  Firefox使用的浏览器引擎SpiderMonkey成为第一个开始致力于实现装饰器的引擎。这样的实现表明该提案已准备好成为规范的完整组成部分。

2022年9月 - Babel7.19.0

  第3阶段装饰器。在编译器中添加支持对于任何提案来说都是非常重要的更新。大多数提案在其标准化计划中都有类似的项目,装饰器提案也不例外。

2022-11 – 宣布TypeScript4.9

  ECMAScript装饰器已列在TS4.9迭代计划中。 然而,一段时间后,TS团队决定将装饰器移至5.0版本。 以下是作者的评论:

虽然装饰器已经进入第3阶段,但我们发现规范中的一些行为需要与支持者讨论。在解决这个问题和审查更改之间,我们预计装饰器将在下一个版本中实现。

  总体而言,这个决定是有道理的,因为他们不想冒险过早地将某个功能纳入TS,尤其是如果它没有成为标准的一部分。这种情况总是有可能发生。尽管在这种情况下,它可能没有第一次实现那么重要。

  在TS4.9中,仅包含了装饰器规范的一小部分-类自动访问器。装饰器规范的这一补充是对实施初期普遍存在的变异的修正。其背后的原因是人们通常希望使属性具有响应性,这意味着当属性发生变化时应该发生某些效果,例如UI重新渲染,例如:

class Dashboard extends HTMLElement {
  @reactive
  tab = DashboardTab.USERS
}

  在旧实现中,使用reactive装饰器时,您必须通过添加额外的访问器来改变类set以get实现所需的行为。使用自动访问器后,此行为现在会更明确地发生,从而允许引擎更好地对其进行优化。

  另一件有趣的事情是装饰器应该如何工作。由于TS团队无法删除在--experimentalDecorators标志下工作的旧实现,他们决定采用以下方法:如果--experimentalDecorators配置中存在该标志,则将使用旧实现。如果不存在此标志,则将使用新实现。

2023-03 – 发布TypeScript5.0

  按照承诺,TS团队TS5.0中发布了装饰器规范的完整版本。

2023-03 – Deno1.32

  尽管在Deno1.32版本中支持TS5.0,但他们决定推迟与装饰器相关的功能。

请注意,ES装饰器尚不受支持,但我们将努力在未来版本中默认启用它们。

2023-05 – Angular v16现已发布

  Angular 16还增加了对ECMAScript装饰器的支持。然而,一些其他围绕装饰器构建的框架表示他们暂时不会对ECMAScript装饰器做出更改。对于其中许多框架来说,两个重要方面是元数据参数装饰器

Kamil Mysliwiec(NextJS的创建者)认为,在实现元数据支持和参数装饰器之前,我们不会支持 JS 装饰器。

2023-08 – 宣布TypeScript5.2

  在TS5.2中,添加了另一项补充装饰器规范的标准–装饰器元数据。该提案背后的主要思想是简化装饰器对使用它们的类元数据的访问。关于语法和用法存在如此多争论的另一个原因是作者必须为此目的创建一个完全独立的提案。

总结

  装饰器提案经过了长达10年的漫长考虑,这确实看起来是一段很长的时间。确实,领先的框架和库早期采用装饰器在发现初始实现的缺点方面发挥了作用。然而,这种早期采用也是一种宝贵的学习经验,凸显了与网络平台协调的重要性,以及开发一种与平台和开发者社区相一致的解决方案的重要性,同时保留装饰器的本质。花在完善提案上的时间最终有助于使其成为JavaScript语言中更强大、更周到的补充。

  装饰器将对我们今天编写应用程序的方式带来重大改变。也许不会立即发生,因为当前规范主要关注类,但随着所有新增功能和正在进行的工作,许多应用程序中的JavaScript代码很快就会看起来不同。我们现在比以往任何时候都更接近最终在规范中看到那些真正的装饰器的那一刻。这是一个令人兴奋的发展,有望增强JavaScript应用程序的表现力和功能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android Google登录接入

官方文献: 1、前期准备: https://developers.google.cn/identity/sign-in/android/legacy-start-integrating?hlzh-cnhttps://developers.google.cn/identity/sign-in/android/legacy-start-integrating?hlzh-cn 2、具体开发: 新版 Googl…

Java 同步锁性能的最佳实践:从理论到实践的完整指南

目录 一、同步锁性能分析 (一)性能验证说明 1. 使用同步锁的代码示例 2. 不使用同步锁的代码示例 3. 结果与讨论 (二)案例初步优化分析说明 1. 使用AtomicInteger原子类尝试优化分析 2. 对AtomicInteger原子类进一步优化 …

Docker+Nginx | Docker(Nginx) + Docker(fastapi)反向代理

在DockerHub搜 nginx,第一个就是官方镜像库,这里使用1.27.2版本演示 1.下载镜像 docker pull nginx:1.27.2 2.测试运行 docker run --name nginx -p 9090:80 -d nginx:1.27.2 这里绑定了宿主机的9090端口,只要访问宿主机的9090端口&#…

C#编写的日志记录组件 - 开源研究系列文章

以前编写过一个日志记录组件的博文,这次发布一个修改过的完善版本。 1、 项目目录; 2、 源码介绍; 1) 实现; 2) 使用; 后面的参数为级别设置,只有大于这个级别的才进行日志记录,限制了日志记录的…

win10+vs2019+cmake+opencv4.10+opencv_contrib编译记录

win10vs2019cmakeopencv4.10opencv_contrib编译记录 第一章 环境配置 本机环境已经安装好vs2019和cmake。 第二章 下载opencv相关 1.Opencv4.10下载 下载链接:opencv 下载时选择"Sources" 2.opencv_contrib 下载链接:opencv_contrib 第三…

前端:HTML (学习笔记)【1】

一,网络编程的三大基石 1,URL (1)url —— 统一资源定位符: 网址——整个互联网中可以唯一且准确的确定一个资源的位置。 【项目外】 网址——https://www.baidu.com/ …

2024年亚太地区数学建模大赛A题-复杂场景下水下图像增强技术的研究

复杂场景下水下图像增强技术的研究 对于海洋勘探来说,清晰、高质量的水下图像是深海地形测量和海底资源调查的关键。然而,在复杂的水下环境中,由于光在水中传播过程中的吸收、散射等现象,导致图像质量下降,导致模糊、…

基于SpringBoot的“广场舞团系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“广场舞团系统”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 系统首页界面图 社团界面图 社团活…

视频流媒体播放器EasyPlayer.js无插件直播流媒体音视频播放器Android端webview全屏调用无效问题

流媒体播放器的核心技术与发展趋势正在不断推动着行业的变革。未来,随着技术的不断进步和应用场景的不断拓展,流媒体播放器将为用户带来更加便捷、高效、个性化的观看体验。同时,流媒体播放器也会成为数字娱乐产业的重要组成部分,…

【Python · PyTorch】卷积神经网络 CNN(LeNet-5网络)

【Python PyTorch】卷积神经网络 CNN(LeNet-5网络) 1. LeNet-5网络※ LeNet-5网络结构 2. 读取数据2.1 Torchvision读取数据2.2 MNIST & FashionMNIST 下载解包读取数据 2. Mnist※ 训练 LeNet5 预测分类 3. EMnist※ 训练 LeNet5 预测分类 4. Fash…

Live2D嵌入前端页面

废话不多说,直接看效果,给页面中嵌入的一个动态的二次元人物,美化页面,实际效果自行查看。 教程开始 一. 把项目拉取到本地 项目地址 自行下载到本地,下载方式自行选择。 二.把项目文件夹放到前端页面目录内 三.把下…

openlayer 将 GeoJSON 格式的 geometry 转换为 feature

openlayer 将 GeoJSON 格式的 geometry 转换为 feature geometry格式如图: 代码: /*** 将 GeoJSON 格式的 geometry 转换为 feature* param geometry* returns*/geoJsonToWkt(geometry) {const { coordinates, type } geometry;let olGeometry;swit…

web应用安全和信息泄露预防

文章目录 1:spring actuator导致的信息泄露1.1、Endpoint配置启用检测1.2、信息泄露复现1.3、防御 2:服务端口的合理使用3:弱口令(密码)管理4:服务端攻击4.1、短信业务,文件上传等资源型接口1、…

基于LSTM的新闻中文文本分类——基于textCNN与textRNN

构建词语字典 def build_vocab(file_path, tokenizer, max_size, min_freq):# 定义词汇表字典:使用 vocab_dic {} 初始化一个空字典,用于存储每个词及其出现频率vocab_dic {}with open(file_path, r, encodingUTF-8) as f:for line in tqdm(f):lin l…

MySQL 的 Change Buffer 是什么?它有什么作用?

MySQL 的 Change Buffer 是什么?它有什么作用? MySQL 是目前广泛使用的开源数据库管理系统,其中的 InnoDB 存储引擎凭借其高性能、高可靠性以及强大的事务支持,成为了默认的存储引擎。在 InnoDB 的众多优化机制中,Cha…

Spark 之 Aggregate

Aggregate 参考链接: https://github.com/PZXWHU/SparkSQL-Kernel-Profiling 完整的聚合查询的关键字包括 group by、 cube、 grouping sets 和 rollup 4 种 。 分组语句 group by 后面可以是一个或多个分组表达式( groupingExpressions )…

C#高级:Winform中的自定义窗体输入

目录 一、多样式输入(无封装) 1.代码 2.效果 二、单输入框封装 1.使用 2.封装 3.效果 三、组合框批量输入封装 1.使用 2.封装 3.效果 一、多样式输入(无封装) 1.代码 private async void button1_Click(object send…

使用GDB或Delve对已经运行起来的Go程序进行远程调试

同步发布在我的博客,欢迎来点赞。 使用 GDB 或 Delve 对已经运行起来的 Go 程序进行远程调试 使用 GDB 或 Delve 对已经运行起来的 Go 程序进行远程调试 背景 Java 程序可以很方便地通过 jdwp 参数指定一个对外端口进行远程调试,如 java \ -agentlib…

简单实现QT对象的[json]序列化与反序列化

简单实现QT对象的[json]序列化与反序列化 简介应用场景qt元对象系统思路实现使用方式题外话 简介 众所周知json作为一种轻量级的数据交换格式,在开发中被广泛应用。因此如何方便的将对象数据转为json格式和从json格式中加载数据到对象中就变得尤为重要。 在python类…

Java开发经验——开发常用工具类

摘要 本文介绍了Java开发中常用的工具类,包括Apache Commons Collections的SetUtils、Google Guava的Sets、Apache Commons Lang的ArrayUtils等,以及它们在集合操作、数组操作、字符串处理、JSON处理等方面的应用。文章还涉及了Optional类、Money工具类…