跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
JavaScript装饰器提案
”︁
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
= JavaScript装饰器提案 = '''装饰器(Decorators)'''是JavaScript的一个[[ECMAScript]]提案(目前处于Stage 3阶段),它提供了一种优雅的方式来修改或增强类及其成员的行为。装饰器本质上是一个高阶函数,能够在不改变原始代码结构的情况下,通过包装目标元素来扩展其功能。 == 基本概念 == 装饰器最初受到Python和TypeScript的启发,旨在为JavaScript开发者提供一种声明式的方式来增强类、方法、属性或访问器。装饰器通过<code>@</code>符号前缀来使用,可以应用于: * 类声明 * 类方法 * 类属性 * 访问器(getter/setter) * 参数(较少使用) 装饰器的核心思想是'''高阶编程'''——即函数可以作为参数传递或返回其他函数。装饰器函数接收目标元素的相关信息,并返回修改后的版本或完全替换它。 == 语法示例 == 以下是一个最简单的装饰器使用示例: <syntaxhighlight lang="javascript"> // 定义一个装饰器函数 function log(target, name, descriptor) { const originalMethod = descriptor.value; descriptor.value = function(...args) { console.log(`调用方法 ${name},参数: ${args}`); return originalMethod.apply(this, args); }; return descriptor; } class Calculator { @log add(a, b) { return a + b; } } const calc = new Calculator(); calc.add(2, 3); // 输出: "调用方法 add,参数: 2,3" 并返回5 </syntaxhighlight> == 装饰器类型 == JavaScript支持多种装饰器类型,每种类型接收不同的参数: === 类装饰器 === 应用于类构造函数,接收目标类作为参数: <syntaxhighlight lang="javascript"> function sealed(constructor) { Object.seal(constructor); Object.seal(constructor.prototype); } @sealed class MyClass {} </syntaxhighlight> === 方法装饰器 === 最常用的装饰器类型,接收三个参数: 1. 目标类的原型(对于静态方法是构造函数) 2. 方法名 3. 属性描述符 === 属性装饰器 === 与方法装饰器类似,但没有描述符参数: <syntaxhighlight lang="javascript"> function readonly(target, name) { Object.defineProperty(target, name, { writable: false }); } class User { @readonly name = 'John'; } </syntaxhighlight> === 访问器装饰器 === 应用于getter/setter方法: <syntaxhighlight lang="javascript"> function configurable(value) { return function(target, name, descriptor) { descriptor.configurable = value; }; } class Person { @configurable(false) get age() { return 30; } } </syntaxhighlight> == 装饰器工厂 == 装饰器工厂是一个返回装饰器函数的函数,允许传递参数来定制装饰器行为: <syntaxhighlight lang="javascript"> function log(message) { return function(target, name, descriptor) { const original = descriptor.value; descriptor.value = function(...args) { console.log(`${message}: ${name}(${args})`); return original.apply(this, args); }; return descriptor; }; } class MathOps { @log('执行加法') add(a, b) { return a + b; } } </syntaxhighlight> == 实际应用场景 == 装饰器在现代JavaScript开发中有多种实用场景: === 日志记录 === 如前面的示例所示,装饰器非常适合用于方法调用的日志记录。 === 性能测量 === 测量方法执行时间: <syntaxhighlight lang="javascript"> function measure(target, name, descriptor) { const original = descriptor.value; descriptor.value = function(...args) { const start = performance.now(); const result = original.apply(this, args); console.log(`${name} 执行时间: ${performance.now() - start}ms`); return result; }; return descriptor; } </syntaxhighlight> === 表单验证 === 验证方法参数: <syntaxhighlight lang="javascript"> function validate(...validators) { return function(target, name, descriptor) { const original = descriptor.value; descriptor.value = function(...args) { validators.forEach((validator, i) => { if (!validator(args[i])) { throw new Error(`参数 ${i} 验证失败`); } }); return original.apply(this, args); }; return descriptor; }; } function isNumber(value) { return typeof value === 'number'; } class MathUtils { @validate(isNumber, isNumber) sum(a, b) { return a + b; } } </syntaxhighlight> === 自动绑定this === 解决回调函数中的this问题: <syntaxhighlight lang="javascript"> function autoBind(target, name, descriptor) { const original = descriptor.value; return { configurable: true, get() { const boundFn = original.bind(this); Object.defineProperty(this, name, { value: boundFn, configurable: true, writable: true }); return boundFn; } }; } class Button { @autoBind handleClick() { console.log(this); // 总是指向Button实例 } } </syntaxhighlight> == 装饰器执行顺序 == 当多个装饰器应用于同一目标时,它们的执行顺序遵循特定规则: <mermaid> graph TD A[装饰器工厂执行] --> B[装饰器函数求值] B --> C[从外到内执行装饰器] C --> D[从下到上执行装饰器] </mermaid> 具体来说: 1. 装饰器工厂按从上到下的顺序执行 2. 装饰器函数按从下到上的顺序执行 例如: <syntaxhighlight lang="javascript"> @decorator1() @decorator2() class Example {} </syntaxhighlight> 执行顺序为: 1. 调用<code>decorator1()</code>工厂函数 2. 调用<code>decorator2()</code>工厂函数 3. 应用<code>decorator2</code>返回的装饰器 4. 应用<code>decorator1</code>返回的装饰器 == 数学表示 == 装饰器可以看作是一个函数变换: <math> decorator : (target, name?, descriptor?) \rightarrow descriptor' </math> 其中: * <math>target</math>是装饰目标 * <math>name</math>是可选的成员名称 * <math>descriptor</math>是可选的属性描述符 * 返回修改后的<math>descriptor'</math> == 注意事项 == 1. 装饰器目前仍是提案,需要使用Babel等转译工具 2. 装饰器不能用于普通函数(只能用于类成员) 3. 过度使用装饰器可能导致代码难以理解 4. 装饰器在编译时执行,而非运行时 == 浏览器支持 == 截至2023年,装饰器提案尚未被所有浏览器原生支持。可以使用以下工具链: * Babel插件:<code>@babel/plugin-proposal-decorators</code> * TypeScript:启用<code>experimentalDecorators</code>选项 == 总结 == JavaScript装饰器提案为元编程提供了强大的工具,允许开发者以声明式的方式修改类行为。虽然目前仍在提案阶段,但已被广泛用于TypeScript和现代前端框架中。合理使用装饰器可以显著提高代码的可重用性和可维护性,但应注意避免过度使用导致的复杂性。 [[Category:编程语言]] [[Category:JavaScript]] [[Category:Javascript现代特性]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)