装饰器模式通过包装方式动态扩展功能而不修改原对象,核心实现包括高阶函数和ES7+装饰器语法,前者兼容性好,后者更声明式;应用场景涵盖日志、缓存、权限校验等横切关注点;与代理模式相比,装饰器更聚焦行为增强,代理则侧重操作拦截;使用时需注意this指向、执行顺序及性能开销,并遵循单一职责和合理封装的最佳实践。

装饰器模式在JavaScript里,核心思想就是不改变一个对象或函数的结构,而是通过“包装”的方式,动态地给它增加新的功能或修改其行为。你可以把它想象成给你的函数或类套上一层层“外衣”,每层外衣都赋予它一些额外的能力。常见的实现方式,要么是传统的函数包装(本质上是高阶函数),要么就是利用ES7+提案中的装饰器语法糖,后者用起来更声明式,也更优雅。
解决方案 在JavaScript中实现装饰器模式,最基础且兼容性最好的方式,就是利用高阶函数来包装现有函数。这就像给一个普通函数加个壳,在它执行前后做点什么。
// 示例1:一个简单的日志记录装饰器(高阶函数形式)
function logExecution(func) {
return function(...args) {
console.log(`[LOG] 准备执行函数: ${func.name || '匿名函数'}`);
const result = func.apply(this, args); // 确保this上下文正确传递
console.log(`[LOG] 函数 ${func.name || '匿名函数'} 执行完毕,结果: ${result}`);
return result;
};
}
// 原始函数
function calculateSum(a, b) {
return a + b;
}
// 应用装饰器
const loggedCalculateSum = logExecution(calculateSum);
console.log('--- 函数装饰器示例 ---');
loggedCalculateSum(10, 20); // 输出日志,并返回30
// 示例2:ES7+ 装饰器语法(针对类和方法,需要Babel等工具支持)
// 注意:这仍然是ECMAScript的一个提案,使用时通常需要转译。
function readOnly(target, key, descriptor) {
descriptor.writable = false; // 让这个属性不可写
return descriptor;
}
function deprecate(message) {
return function(target, key, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
console.warn(`[DEPRECATION] 方法 ${key} 已废弃: ${message}`);
return originalMethod.apply(this, args);
};
return descriptor;
};
}
class Product {
constructor(name, price) {
this.name = name;
this._price = price;
}
@readOnly // 装饰器应用于属性
get price() {
return this._price;
}
@deprecate('请使用 calculateFinalPrice 代替。') // 装饰器应用于方法
calculateOldPrice(quantity) {
return this._price * quantity;
}
calculateFinalPrice(quantity, discount = 0) {
return (this._price * quantity) * (1 - discount);
}
}
console.log('\n--- ES7+ 装饰器示例 ---');
const laptop = new Product('Laptop', 1200);
// laptop.price = 1300; // 这行会报错或静默失败,因为price是只读的
console.log(`产品价格: ${laptop.price}`); // 1200
laptop.calculateOldPrice(2); // 会输出废弃警告
console.log(`最终价格: ${laptop.calculateFinalPrice(2, 0.1)}`); // 2160上面的高阶函数方式,我觉得是最能体现“包装”这个概念的,也最直接。而ES7+的装饰器语法,说实话,它更像是一种语法糖,让这种包装行为变得更具声明性,代码看起来也更简洁,但底层逻辑依然是类似的。
装饰器模式的应用场景其实挺广的,我个人觉得它最出彩的地方在于能优雅地实现“横切关注点”的分离,也就是那些散落在多个功能模块中,但又不是核心业务逻辑的代码,比如日志、缓存、权限校验、性能监控、输入验证等等。
举几个例子:
this
bind
这玩意儿,用好了是真的能让代码变得更干净、更模块化,职责分离得特别清晰。
这三者在某种程度上都实现了行为的增强或修改,但它们的侧重点、实现方式和应用场景还是有挺大区别的。我个人是这样理解的:
相同点: 它们都能在不直接修改原始代码的情况下,为对象或函数添加新功能,或者改变其现有行为。目的都是为了提高代码的复用性和可维护性。
不同点:
高阶函数 (Higher-Order Functions, HOFs):
ES7+ 装饰器 (Decorators):
@
代理模式 (Proxy Pattern):
Proxy
选择哪个,真的要看具体场景。如果只是简单地包装函数行为,高阶函数足够了。如果想让类或方法的增强更具声明性,且不介意引入编译工具,ES7+装饰器很棒。如果需要对对象的各种操作进行全面拦截和控制,那
Proxy
实现装饰器这事儿吧,说起来简单,做起来可能有些门道,特别是ES7+的装饰器,因为是提案,坑可能更多点。我总结了一些常见的陷阱和一些我个人觉得不错的实践方法。
常见陷阱:
this
this
this
func.apply(this, args)
func.call(this, ...args)
最佳实践:
this
this
apply
call
@deprecate('消息')总的来说,装饰器是一个非常强大的工具,它能让你的代码更优雅,更具扩展性。但就像所有强大的工具一样,用得好不好,关键在于理解其背后的原理,并结合实际场景做出明智的选择。
以上就是JS如何实现装饰器模式的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号