网站源码风险,别样海外购怎么开店,如何设计一个app,西安网站设计师基础问答问#xff1a;什么是装饰器#xff1f;有什么作用#xff1f;答#xff1a;装饰器是一种元编程语法#xff0c;可以在不修改原有代码的前提下#xff0c;动态地为类、方法、属性等添加一些能力#xff0c;本质上还是一个函数#xff0c;它接收目标对象、属性…基础问答问什么是装饰器有什么作用答装饰器是一种元编程语法可以在不修改原有代码的前提下动态地为类、方法、属性等添加一些能力本质上还是一个函数它接收目标对象、属性名、属性描述符或类本身作为参数返回修改后的目标对象或属性描述符。在使用的时候是声明式的使用在装饰器函数前加上一个 符号在需要使用的函数、类、方法、属性上一行的位置添加如下// 定义类装饰器为类添加版本信息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.0MyClass.logVersion(); // 输出版本号1.0.0如果你不想在本地运行可以在 Typescript Playground 编译运行。扩展延伸先说个题外话你需要知道的是装饰器现在还是在提案阶段TC39 Stage 3自 2015 年提出以来到现在依然没有成为规范的一部分但是目前已经广泛的应用在前端的很多库中如 MobX 、Angular 依赖注入等只是我们在使用上略微复杂需要通过一些编译工具如 Babel或 Typescript 来进行转换。基本使用装饰器可用于修饰类、类方法、类属性、访问器getter/setter 等不同修饰的场景下的语法和参数略有一些差异。类装饰器一般用于修饰整个类可以为类添加静态属性和方法参考基础问答部分代码也可以修改类的构造函数示例如下// 定义类装饰器为实例添加默认属性function addDefaultProps(props: Recordstring, 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 }方法装饰器方法装饰器用于修饰类的方法接收三个参数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属性装饰器用于修饰类的属性接收两个参数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 范围内访问器装饰器用于修饰类的 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;}// 使用装饰器修饰gettersanitizeget content() {return this._content;}}// 测试const msg new Message(script恶意代码/script 正常内容);console.log(msg.content); // 输出恶意代码 正常内容已过滤script标签需要注意的是JavaScript 没有支持装饰器前面说了装饰器还在提案阶段要使用这个特性需要通过 Typescript 或 babel 等编译器而且随着版本的更迭有些写法会有不同如果你运行了这个表格工作原理和 JavaScript 中的 class、async/await 类似装饰器也是一个语法糖底层还是通过函数调用实现。编译过程对于类装饰器当使用装饰器函数修饰一个类的时候顺序是先定义这个类然后在这个使用装饰器函数包裹这个类作为参数传递最后用函数返回值覆盖原来的类。你可以简单的视为// 源码decoratorclass MyClass {}// 编译后近似class MyClass {}MyClass decorator(MyClass) || MyClass;更详细的编译结果可以在自己运行一次 TypeScript 的编译得到。对于方法装饰器很容易根据上面的想到其编译过程是在类定义之后将方法作为参数传递执行时机装饰器在类定义阶段执行而非实例化阶段这意味着装饰器的逻辑在类被定义时就会执行而非调用方法或创建实例时装饰器内部无法访问类的实例this指向原型对象或类本身而非实例。function logWhenDefined(target) {console.log(类被定义了);return target;}logWhenDefinedclass MyClass {}// 输出类被定义了此时还未创建实例面试追问装饰器和高阶函数的区别是什么相同点两者都可实现功能扩展本质都是函数不同点装饰器是语法糖有明确的语法规范符号仅用于修饰类或类成员高阶函数是函数式编程概念指接收函数作为参数或返回函数的函数适用范围更广可修饰任何函数不限于类方法装饰器在类定义阶段执行高阶函数在函数调用阶段执行。这里给出一个高阶函数示例// 高阶函数实现日志功能与方法装饰器效果类似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)装饰器可以装饰函数和对象吗装饰器仅支持类和类成员方法、属性、访问器不支持普通函数或对象是因为函数存在函数变量提升装饰器执行时机定义阶段与函数提升可能冲突导致逻辑混乱如果想实现类似的效果建议是通过高阶函数来实现参考上一问。实际开发过程中你在什么场景下使用装饰器日志与监控为方法添加调用日志、性能统计如上述log和measureTime装饰器权限控制在需要权限的方法前添加权限校验如requirePermission缓存处理为耗时方法添加结果缓存避免重复计算框架集成Angular用装饰器定义组件Component、服务InjectableMobX用observable、action装饰器管理状态Vue Class Component用Component、Prop装饰器定义 Vue 组件数据校验为类属性添加类型或范围校验如range装饰器。使用装饰器的时候遇到过什么问题兼容性装饰器仍为提案需通过 Babel/TypeScript 转译不同转译工具可能有语法差异执行时机装饰器在类定义时执行避免在装饰器中编写依赖实例的逻辑原型链影响修改类或方法时需注意保持原型链完整如单例装饰器中继承原类原型性能开销装饰器会增加函数调用层级复杂装饰器可能影响性能需适度使用。你写的这个方法装饰器为什么我运行报错这个就是一个踩坑的地方由于装饰器并没有正式的落地标准所以你会发现有一些网上的装饰器代码你运行不起来注意切换Typescript或babel的插件版本去解决。如本文中的代码在 Typescript 3.x 版本中都可以正常使用但是升级版本后有些就不兼容了。