javascript - Typescript/Javascript 自定义属性装饰器

标签 javascript angularjs typescript

我刚刚开始更深入地学习 Typescript 和 ES6 功能,我对您应该如何创建自定义属性装饰器以及它实际上如何工作有一些误解。

这是我关注的来源 Source1 Source2

这是我的自定义除臭剂。

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 with Items value, but instead is undefined, why?

当你的 MyClass 类被实例化并且你的装饰器代码被运行时,对象的所有属性的值都是 undefined (即使你使用 TypeScript 属性初始化器,而你不是)。

Shouldn't this refer to the Required?

是的,我认为在您的示例中确实如此。但是在你的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 parameter val 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/

相关文章:

typescript - 组合类型保护签名

javascript - Ajax 功能不适用于移动浏览器

javascript - AngularJs 和 ui-grid : grid is ignoring gridOptions

javascript - webpack 2.2.1 以错误的顺序/位置排列依赖项

angularjs - 提供给 routeProvider 的调试路由

javascript - Karma + ui-router 失败 : Cannot read property 'isDefined' of undefined

node.js - 将 typescript 定义模块声明匹配到 Node 模块导入

javascript - 使用 Pyston 到 LLVM,然后使用 Emiscripten 到 Javascript

javascript - 从没有小程序的网页访问客户端的扫描仪

javascript - 类比 htmls <script src =""> xaml 标签