我刚刚开始更深入地学习 Typescript 和 ES6 功能,我对您应该如何创建自定义属性装饰器以及它实际上如何工作有一些误解。
这是我的自定义除臭剂。
export const Required = (target: Object, key: string) => {
let value: any = target[key];
const getter = () => {
if (value !== undefined) return value;
throw new RequiredPropertyError(MetadataModule.GetClassName(target), key, ErrorOptions.RequiredProperty)
}
const setter = (val) => value = val;
if (delete this[key]) {
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true,
});
}
}
它是这样应用的
export classMyClass{
@Required
public Items: number[];
}
我不明白的是为什么它的工作方式与您期望的不同。很好,但我不知道它是否符合我们称之为“装饰哲学”的观点,
我不明白的解释一下
从第一行代码开始。
let value: any = target[key];
我希望 value
会使用 Items
值进行初始化,但实际上是 undefined
,为什么?如何?我真的不明白。
我已经关注了这两个来源,第一件让我感到困惑的事情是一个使用 target[key]
来初始化 value
而另一个使用this[key]
,this
实际上不应该引用Required。
我也觉得困惑的是这部分
if (delete this[key]) {
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true,
});
}
首先,为什么我需要删除这个[key]?根据我的理解,在我的这种情况下,这应该引用当前对象上下文 Required
,并且在调试时也是如此。
其次,在我的示例 MyClass
中,Object.defineProperty 将使用目标类上的键名称创建一个属性,但是这个属性不是已经存在了吗?
向前移动并使用 setter 设置 value
,setter 参数 val
如何知道它应该保存什么数据?我的意思是它会从哪里来?
谢谢大家。
最佳答案
里面有很多问题,但我会尽量一一解答:)
I would expect that the
value
would be initialized withItems
value, but instead isundefined
, why?
当你的 MyClass
类被实例化并且你的装饰器代码被运行时,对象的所有属性的值都是 undefined
(即使你使用 TypeScript 属性初始化器,而你不是)。
Shouldn't
this
refer to theRequired
?
是的,我认为在您的示例中确实如此。但是在你的Source1 link ,装饰器是使用函数表达式定义的(function logProperty()
);在您的示例中,您已将其切换为箭头函数表达式 (const Required = ( ... ) =>
)。此开关很可能会更改 this
所指的内容。为了安全起见,请将其切换为 target[key]
。
Why I need to delete this[key]?
此代码块正在删除原始的 Items
属性并将其替换为允许您监视变量的获取和设置的同名属性。 delete this[key]
行防止属性不可配置的情况。 (The delete
operator returns false
if the property in question is non-configurable:)。
Object.defineProperty will create a property with the name of the key on the target class in my case
MyClass
, but isn't this property already there?
是的,如上所述 - 此代码正在用新属性替换该属性。设置新属性是为了让您观察此变量的获取和设置。
Moving forward and setting the
value
using the setter, how does the setter parameterval
know what data it should hold ? I mean where is it coming ?
设置新的 Items
属性后,将调用 setter
函数,并将该属性的新值作为参数(此 setter
函数之前使用 Object.defineProperty
设置为 setter 函数。此setter
函数的实现设置value
,它是对target[key]
的引用。因此,Items
的值得到更新。
为了更好地理解这一切是如何工作的,尝试添加一些日志语句,然后尝试获取/设置 Items
属性:
export const Required = (target: Object, key: string) => {
let value: any = target[key];
console.log('Initialize the Required decorator; value:', value);
const getter = () => {
console.log('Inside the getter; value is:', value);
if (value !== undefined) return value;
throw new RequiredPropertyError(MetadataModule.GetClassName(target), key, ErrorOptions.RequiredProperty);
};
const setter = val => {
console.log('Inside the setter; val is: ', val, 'value is:', value);
return (value = val);
};
if (delete this[key]) {
console.log('Replacing the "' + key + '" property with a new, configured version');
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
};
export class MyClass {
@Required
public Items: number[];
}
// instantiated your class
var mc = new MyClass();
// set the Items property
mc.Items = [4, 5, 6];
// get the value with no Errors
mc.Items;
// set the Items property to undefined
mc.Items = undefined;
// get the value - an Error is thrown
mc.Items;
关于javascript - Typescript/Javascript 自定义属性装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48703242/