我正在使用以下方法使用装饰器对TypeScript getter进行记忆,但我想知道是否有更好的方法。我正在使用npm中流行的memoizee包,如下所示:
import { memoize } from '@app/decorators/memoize'
export class MyComponent {
@memoize()
private static memoizeEyeSrc(clickCount, maxEyeClickCount, botEyesDir) {
return clickCount < maxEyeClickCount ? botEyesDir + '/bot-eye-tiny.png' : botEyesDir + '/bot-eye-black-tiny.png'
}
get leftEyeSrc() {
return MyComponent.memoizeEyeSrc(this.eyes.left.clickCount, this.maxEyeClickCount, this.botEyesDir)
}
}而memoize装饰器是:
// decorated method must be pure
import * as memoizee from 'memoizee'
export const memoize = (): MethodDecorator => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const func = descriptor.value
descriptor.value = memoizee(func)
return descriptor
}
}有没有一种方法可以不用在MyComponent中使用两个单独的函数,而直接将装饰器添加到TypeScript getter中?
这里的一个考虑因素是修饰函数必须是纯的(在这个场景中),但是如果你有一个不能满足这个问题的答案,你可以随意忽略它,因为我对如何处理这个问题有普遍的兴趣。
发布于 2019-05-15 20:19:06
装饰器可以扩展为同时支持原型方法和getter:
export const memoize = (): MethodDecorator => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
if ('value' in descriptor) {
const func = descriptor.value;
descriptor.value = memoizee(func);
} else if ('get' in descriptor) {
const func = descriptor.get;
descriptor.get = memoizee(func);
}
return descriptor;
}
}并直接在getter上使用:
@memoize()
get leftEyeSrc() {
...
}发布于 2019-05-16 01:58:28
基于@estus的回答,这是我最终想出来的:
@memoize(['this.eyes.left.clickCount'])
get leftEyeSrc() {
return this.eyes.left.clickCount < this.maxEyeClickCount ? this.botEyesDir + '/bot-eye-tiny.png' : this.botEyesDir + '/bot-eye-black-tiny.png'
}而memoize装饰器是:
// decorated method must be pure when not applied to a getter
import { get } from 'lodash'
import * as memoizee from 'memoizee'
// noinspection JSUnusedGlobalSymbols
const options = {
normalizer(args) {
return args[0]
}
}
const memoizedFuncs = {}
export const memoize = (props: string[] = []): MethodDecorator => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
props = props.map(prop => prop.replace(/^this\./, ''))
if ('value' in descriptor) {
const valueFunc = descriptor.value
descriptor.value = memoizee(valueFunc)
} else if ('get' in descriptor) {
const getFunc = descriptor.get
// args is used here solely for determining the memoize cache - see the options object
memoizedFuncs[propertyKey] = memoizee((args: string[], that) => {
const func = getFunc.bind(that)
return func()
}, options)
descriptor.get = function() {
const args: string[] = props.map(prop => get(this, prop))
return memoizedFuncs[propertyKey](args, this)
}
}
return descriptor
}
}这允许传递一个字符串数组,其中确定哪些属性将用于memoize缓存(在本例中,只有1个prop - clickCount -是变量,其他2个是常量)。
memoizee选项声明只有arg到memoizee((args: string[], that) => {...})的第一个数组用于记忆目的。
我还在试着弄明白这段代码有多美!今天一定过得很愉快。感谢我的朋友和救世主叶斯华:)
https://stackoverflow.com/questions/56148490
复制相似问题