面试题答案
一键面试处理装饰器函数内部作用域问题
- 箭头函数的使用:在TypeScript装饰器函数中,使用箭头函数可以确保函数内部的
this
指向与外部作用域一致。因为箭头函数没有自己的this
绑定,它会继承外部作用域的this
。例如:function myDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { // 这里的this是类实例,因为箭头函数继承了外部作用域的this const context = this; console.log('Before method execution in decorator', context); const result = originalMethod.apply(context, args); console.log('After method execution in decorator', context); return result; }; return descriptor; } class MyClass { @myDecorator myMethod() { console.log('Inside myMethod'); } }
- 保存外部作用域的
this
:在普通函数中,可以通过保存外部作用域的this
到一个变量(通常命名为self
或that
),然后在函数内部使用这个变量来访问外部作用域的this
。例如:function myDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; const self = this; descriptor.value = function (...args: any[]) { console.log('Before method execution in decorator', self); const result = originalMethod.apply(this, args); console.log('After method execution in decorator', self); return result; }; return descriptor; } class MyClass { @myDecorator myMethod() { console.log('Inside myMethod'); } }
获取类实例上下文
- 装饰器应用于类方法时:当装饰器应用于类的方法时,在装饰器函数中,
this
在默认情况下指向的是该方法的调用者,也就是类的实例。例如,在上述代码中,在myDecorator
的descriptor.value
函数内部,this
就是MyClass
的实例。 - 编译阶段代码转换:在编译阶段,TypeScript会将装饰器语法转换为JavaScript代码。以
@myDecorator
应用于myMethod
为例,转换后的JavaScript代码大致如下(简化示意):
在这个转换后的代码中,可以看到装饰器函数通过function myDecorator(target, propertyKey, descriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args) { const context = this; console.log('Before method execution in decorator', context); const result = originalMethod.apply(context, args); console.log('After method execution in decorator', context); return result; }; return descriptor; } class MyClass { myMethod() { console.log('Inside myMethod'); } } const myClassProto = MyClass.prototype; const myMethodDescriptor = Object.getOwnPropertyDescriptor(myClassProto,'myMethod'); Object.defineProperty(myClassProto,'myMethod', myDecorator(myClassProto,'myMethod', myMethodDescriptor));
this
获取到了类实例的上下文,并对方法进行了包装。这样在方法调用时,就可以在装饰器逻辑中访问类实例的上下文。