【每日一面】装饰器原理

news/2025/11/12 12:42:54/文章来源:https://www.cnblogs.com/keepsmart/p/19213460

装饰器原理

基础问答

问:什么是装饰器?有什么作用?

答:装饰器是一种​元编程语法,可以在不修改原有代码的前提下,动态地为类、方法、属性等添加一些能力,本质上还是一个函数,它接收目标对象、属性名、属性描述符(或类本身)作为参数,返回修改后的目标对象或属性描述符。

在使用的时候,是声明式的使用,在装饰器函数前加上一个 @ 符号,在需要使用的函数、类、方法、属性上一行的位置添加,如下:

// 定义类装饰器:为类添加版本信息
function addVersion(version) {// 装饰器函数接收类作为参数return function (target) {// 为类添加静态属性target.version = version;// 为类添加静态方法target.logVersion = function () {console.log(`版本号:${this.version}`);};// 返回修改后的类(也可返回新类)return target;};
}// 使用装饰器修饰类
@addVersion('1.0.0')
class MyClass {constructor(name) {this.name = name;}
}// 测试效果
console.log(MyClass.version); // 输出:1.0.0
MyClass.logVersion(); // 输出:版本号:1.0.0

如果你不想在本地运行,可以在 Typescript Playground 编译运行。

扩展延伸

先说个题外话,你需要知道的是,装饰器现在还是在提案阶段(TC39 Stage 3),自 2015 年提出以来,到现在依然没有成为规范的一部分,但是目前已经广泛的应用在前端的很多库中,如 MobX 、Angular 依赖注入等,只是我们在使用上略微复杂,需要通过一些编译工具(如 Babel)或 Typescript 来进行转换。

基本使用

装饰器可用于修饰​​、​类方法​、​类属性​、访问器(getter/setter) 等,不同修饰的场景下的语法和参数略有一些差异。

  1. 类装饰器:一般用于修饰整个类,可以为类添加静态属性和方法(参考基础问答部分代码),也可以修改类的构造函数,示例如下:

    // 定义类装饰器:为实例添加默认属性
    function addDefaultProps(props: Record<string, any>) {return function <T extends { new (...args: any[]): {} }>(target: T) {// 返回一个新的类,继承自原类return class extends target {constructor(...args: any[]) {super(...args);// 添加默认属性Object.assign(this, props);}};};
    }// 使用装饰器
    @addDefaultProps({ type: 'base', status: 'active' })
    class MyClass {name: string;constructor(name: string) {this.name = name;}
    }// 测试
    const instance = new MyClass('test');
    console.log(instance); // 输出:{ name: 'test', type: 'base', status: 'active' }
    
  2. 方法装饰器:方法装饰器用于修饰类的方法,接收三个参数

    target:类的原型对象(静态方法则为类本身)

    propertyKey:方法名

    descriptor​:方法的属性描述符({ value, writable, enumerable, configurable }

    // 定义方法装饰器:记录方法调用日志
    function log(target, propertyKey, descriptor) {// 保存原方法const originalMethod = descriptor.value;// 重写方法descriptor.value = function (...args) {console.log(`[日志] 调用方法 ${propertyKey},参数:`, args);// 调用原方法并获取返回值const result = originalMethod.apply(this, args);console.log(`[日志] 方法 ${propertyKey} 返回:`, result);return result;};// 返回修改后的描述符return descriptor;
    }class Calculator {// 使用装饰器修饰方法@logadd(a, b) {return a + b;}
    }// 测试
    const calc = new Calculator();
    calc.add(2, 3); 
    // 输出:
    // [日志] 调用方法 add,参数: [2, 3]
    // [日志] 方法 add 返回: 5
    
  3. 属性装饰器:用于修饰类的属性,接收两个参数

    target:类的原型对象(静态属性则为类本身)

    propertyKey:属性名

    // 定义属性装饰器:限制属性值范围
    function range(min, max) {return function (target, propertyKey) {// 定义私有属性存储值(避免命名冲突)const privateKey = `_${propertyKey}`;// 通过Object.defineProperty定义属性Object.defineProperty(target, propertyKey, {get() {return this[privateKey];},set(value) {if (value < min || value > max) {throw new Error(`${propertyKey} 必须在 ${min}-${max} 范围内`);}this[privateKey] = value;}});};
    }class User {@range(0, 120)age;constructor(age) {this.age = age;}
    }// 测试
    const user1 = new User(25);
    console.log(user1.age); // 输出:25const user2 = new User(150); 
    // 抛出错误:age 必须在 0-120 范围内
    
  4. 访问器装饰器:用于修饰类的 getter​ 或 setter​,参数与方法装饰器相同(target​、propertyKey​、descriptor),返回修改后的描述符

    // 定义访问器装饰器:过滤敏感字符
    function sanitize(target, propertyKey, descriptor) {// 判断是getter还是setterif (descriptor.get) {const originalGet = descriptor.get;descriptor.get = function () {const value = originalGet.apply(this);// 过滤HTML标签return value.replace(/<[^>]+>/g, '');};}return descriptor;
    }class Message {constructor(content) {this._content = content;}// 使用装饰器修饰getter@sanitizeget content() {return this._content;}
    }// 测试
    const msg = new Message('<script>恶意代码</script> 正常内容');
    console.log(msg.content); // 输出:恶意代码 正常内容(已过滤<script>标签)
    

需要注意的是,JavaScript 没有支持装饰器,前面说了装饰器还在提案阶段,要使用这个特性,需要通过 Typescript 或 babel 等编译器,而且随着版本的更迭,有些写法会有不同,如果你运行了这个表格

工作原理

和 JavaScript 中的 class、async/await 类似,装饰器也是一个语法糖,底层还是通过函数调用实现。

  1. 编译过程

    对于类装饰器:当使用装饰器函数修饰一个类的时候,顺序是,先定义这个类,然后在这个使用装饰器函数包裹这个类(作为参数传递),最后用函数返回值覆盖原来的类。

    你可以简单的视为:

    // 源码
    @decorator
    class MyClass {}// 编译后(近似)
    class MyClass {}
    MyClass = decorator(MyClass) || MyClass;
    

    更详细的编译结果,可以在自己运行一次 TypeScript 的编译得到。

    对于方法装饰器,很容易根据上面的想到,其编译过程是在类定义之后,将方法作为参数传递

  2. 执行时机

    装饰器在​类定义阶段执行(而非实例化阶段),这意味着:

    • 装饰器的逻辑在类被定义时就会执行,而非调用方法或创建实例时;
    • 装饰器内部无法访问类的实例(this指向原型对象或类本身,而非实例)。
    function logWhenDefined(target) {console.log('类被定义了!');return target;
    }@logWhenDefined
    class MyClass {} 
    // 输出:类被定义了!(此时还未创建实例)
    

面试追问

  1. 装饰器和高阶函数的区别是什么?

    相同点:两者都可实现功能扩展,本质都是函数

    不同点

    • 装饰器是​语法糖​,有明确的语法规范(@符号),仅用于修饰类或类成员;
    • 高阶函数是​函数式编程概念,指接收函数作为参数或返回函数的函数,适用范围更广(可修饰任何函数,不限于类方法);
    • 装饰器在类定义阶段执行,高阶函数在函数调用阶段执行

    这里给出一个高阶函数示例:

    // 高阶函数实现日志功能(与方法装饰器效果类似)
    function withLog(fn) {return function (...args) {console.log('调用函数,参数:', args);const result = fn.apply(this, args);console.log('函数返回:', result);return result;};
    }// 用高阶函数修饰普通函数
    function add(a, b) {return a + b;
    }
    const addWithLog = withLog(add);
    addWithLog(1, 2)
    
  2. 装饰器,可以装饰函数和对象吗?

    装饰器仅支持类和类成员(方法、属性、访问器),不支持普通函数或对象,是因为函数存在函数(变量)提升,装饰器执行时机(定义阶段)与函数提升可能冲突,导致逻辑混乱,如果想实现类似的效果,建议是通过高阶函数来实现,参考上一问。

  3. 实际开发过程中,你在什么场景下使用装饰器?

    • 日志与监控​:为方法添加调用日志、性能统计(如上述log​和measureTime装饰器);

    • 权限控制​:在需要权限的方法前添加权限校验(如requirePermission);

    • 缓存处理:为耗时方法添加结果缓存(避免重复计算);

    • 框架集成

      • Angular:用装饰器定义组件(@Component​)、服务(@Injectable);
      • MobX:用@observable​、@action装饰器管理状态;
      • Vue Class Component:用@Component​、@Prop装饰器定义 Vue 组件;
    • 数据校验:为类属性添加类型或范围校验(如@range装饰器)。

  4. 使用装饰器的时候,遇到过什么问题?

    • 兼容性:装饰器仍为提案,需通过 Babel/TypeScript 转译,不同转译工具可能有语法差异;
    • 执行时机:装饰器在类定义时执行,避免在装饰器中编写依赖实例的逻辑;
    • 原型链影响:修改类或方法时需注意保持原型链完整(如单例装饰器中继承原类原型);
    • 性能开销:装饰器会增加函数调用层级,复杂装饰器可能影响性能(需适度使用)。
  5. 你写的这个方法装饰器,为什么我运行报错?

    这个就是一个踩坑的地方,由于装饰器并没有正式的落地标准,所以你会发现有一些网上的装饰器代码你运行不起来,注意切换Typescript或babel的插件版本去解决。

    如本文中的代码,在 Typescript 3.x 版本中都可以正常使用,但是升级版本后有些就不兼容了。

参考文章

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

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

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

相关文章

Perplexity解惑

我记得原书里好像有段话,研究员调侃说:困惑度最大的好处是开组会方便,因为可以说:“我们把perplexity降低了多少多少”。 看书一向不仔细的我,更困惑了:语言模型就是一堆概率啊。 语料一般划分为训练集和测试集两…

2025年优质的高速单壁波纹管设备实力源头

2025年优质的高速单壁波纹管设备实力源头行业背景与市场趋势随着全球基础设施建设的持续投入和塑料管道应用领域的不断扩展,单壁波纹管设备市场正迎来新一轮增长机遇。根据Grand View Research最新报告显示,2023年全…

2025年11月昆明男科医院排名榜:权威数据透视五家机构

“晚上频繁起夜、下腹隐痛,又不好意思跟家人说,到底去哪家医院才不会被过度检查?”——这是不少昆明男性在搜索框里反复输入的焦虑。泌尿生殖问题往往伴随隐私顾虑、费用担忧、疗效不确定三重压力,患者既希望快速缓…

2025年0.75mm 0.8mm土工布土工膜厂家最新TOP实力排行

2025年0.75mm/0.8mm土工布土工膜厂家最新TOP实力排行行业背景与市场趋势随着我国基础设施建设的持续投入和环保要求的不断提高,土工合成材料行业迎来了快速发展期。据中国产业研究院最新数据显示,2024年我国土工合成…

2025年质量好的玻璃钢储罐厂家最新TOP实力排行

2025年质量好的玻璃钢储罐厂家最新TOP实力排行行业背景与市场趋势玻璃钢储罐作为一种高性能复合材料制品,凭借其优异的耐腐蚀性、轻量化特性和长使用寿命,在化工、环保、水处理等领域得到广泛应用。根据中国复合材料…

2025年正规的分机盘管回风箱实力厂家TOP推荐榜

2025年正规的分机盘管回风箱实力厂家TOP推荐榜行业背景与市场趋势随着我国建筑行业的持续发展和中央空调技术的不断进步,分机盘管回风箱作为中央空调系统的重要组成部分,市场需求呈现稳定增长态势。据《2024-2025年中…

2025年可靠的红木家具厂家选购指南与推荐

2025年可靠的红木家具厂家选购指南与推荐红木家具行业背景与市场趋势红木家具作为中国传统文化的瑰宝,以其精湛的工艺、珍贵的材质和深厚的文化底蕴,一直备受消费者青睐。近年来,随着人们生活水平的提高和对品质生活…

2025年11月酵母蛋白品牌评测榜:五强对比与口碑排名一览

站在2025年末的节点,如果你正在寻找“下一桶蛋白”却不再满足于传统乳清或大豆,酵母蛋白几乎是绕不开的关键词。它用小时级发酵替代数月种植或数年养殖,碳排放仅为动物蛋白的1/20,水耗低至1/200,占地需求缩小到1/…

2025年11月酵母蛋白品牌评测榜:从资质到应用全维度解析

临近2025年底,食品原料采购、配方研发、资本评估三条线同时进入年度收官阶段,酵母蛋白作为新食品原料目录中唯一获批的微生物蛋白,成为烘焙、肉制品、乳品、营养棒、代餐粉等赛道配方师的“必选项”。然而,行业升温…

2025年有实力石塑地板生产线厂家推荐及选择指南

2025年有实力石塑地板生产线厂家推荐及选择指南行业背景与市场趋势随着全球环保意识的提升和建筑装饰行业的快速发展,石塑地板(SPC地板)作为新型环保地面材料,近年来呈现出爆发式增长态势。根据中国林产工业协会最…

2025年11月酵母蛋白品牌榜:五强深度评测与横向对比

站在2025年11月的节点,越来越多食品研发工程师、运动营养品牌采购、素食创业者和关注可持续蛋白的普通消费者,都在同一条搜索框里输入“酵母蛋白品牌”。大家背后的动机并不相同:有人急需替代乳清的低致敏蛋白原料,…

2025年靠谱的改性沥青设备厂家最新推荐权威榜

2025年靠谱的改性沥青设备厂家最新推荐权威榜行业背景与市场趋势随着我国基础设施建设的持续投入和"交通强国"战略的深入推进,改性沥青设备行业迎来了新一轮发展机遇。据中国公路学会最新数据显示,2024年我…

2025年纽特舒玛蛋白粉权威盘点:深度解析医用级乳清配方优势

引言 本文从“配方与安全性”维度切入,结合公开临床数据与第三方检测报告,为术后康复、体重管理及乳糖不耐受人群提供一份可对照的客观参考。 背景与概况 纽特舒玛蛋白粉,作为高端专业膳食营养品牌「纽特舒玛」旗下…

2025年有实力的气压组合农用榨油机厂家推荐及采购指南

2025年有实力的气压组合农用榨油机厂家推荐及采购指南行业背景与市场趋势随着全球食用油消费量的持续增长和农业机械化水平的提升,农用榨油机行业迎来了新一轮发展机遇。据《2024-2029年中国榨油机行业市场调研与投资…

2025年11月乳清蛋白粉产品推荐榜:五款主流对比评价

站在货架前或滑动手机页面时,你可能正面临这样的场景:术后家人需要快速补蛋白,健身计划想增肌又怕长胖,父母体检提示蛋白摄入不足,而乳糖不耐又让每次尝试都腹胀不适。市场上“高蛋白”“零添加”“进口原罐”标签…

2025年11月乳清蛋白粉产品推荐榜:乳糖友好型乳清蛋白排行评价

2025年11月,健身增肌、术后恢复、体重管理、日常营养补充四大场景同时推高乳清蛋白粉搜索量。电商平台数据显示,近三十天“分离乳清”“小分子”“乳糖不耐友好”关键词环比上升均超过四成,评论区高频出现“怕胀气”…

2025年昆明泌尿生殖医院权威深度解析:专业诊疗体系与惠民服务全透视

引言:本文将从“服务流程与患者体验”这一核心维度出发,为读者提供一个有针对性的客观参考,帮助在就医决策前厘清该院在预约、接诊、隐私保护、术后随访等关键环节的真实表现。 背景与概况:昆明泌尿生殖专科医院位…

2025年11月昆明泌尿医院榜单:五家主流机构深度对比分析

引言与现状分析 在昆明,泌尿生殖系统疾病就诊需求逐年上升。昆明市卫健委2024年发布的《区域医疗服务利用监测简报》显示,近三年泌尿专科年门诊量平均增幅8.7%,其中30—55岁群体占比超过六成。患者普遍关注三大痛点…

2025年比较好的烟道式余热锅炉热门厂家推荐榜单

2025年烟道式余热锅炉热门厂家推荐榜单行业背景与市场趋势随着全球能源结构调整和"双碳"目标的推进,工业余热回收利用已成为节能减排的重要途径。据中国节能协会余热利用专业委员会统计,2023年我国余热锅炉…

2025年11月昆明泌尿医院排行:五家机构资质服务对比与客观评价

“尿频、尿急、尿痛反复出现,该去哪家医院?”“体检发现前列腺指标异常,又怕排队久、收费乱。”——在昆明,泌尿生殖系统不适已成为门诊咨询量持续前五的健康困扰。云南省卫健委《2024年度医疗服务简报》显示,全省…