javascript - 带有属性装饰器的 TypeScript 类就像静态的一样

标签 javascript properties typescript decorator

我编写了一个带有属性装饰器的类,它在设置装饰属性时在类中设置一个标志。我还希望能够从该类的一个实例复制到另一个实例。问题是,当我在一个对象上设置属性值时,另一个对象上的属性值也会发生变化,就好像该属性是静态的一样。我是 JavaScript 和 TypeScript 的新手。我错过了什么?

运行下面的文本代码将记录:

Setting propNum from undefined to 0
testclass.ts:18 Setting propNum from 0 to 123
test.spec.ts:13 t1.propNum = 123
test.spec.ts:14 t2.propNum = 123

t1.propNum 仍应为零

装饰器

//
// property decorator to set dirty flag automatically for any decorated property
//
function testProperty( target: any, key: string ) {

    // property value
    var _val = this[key];

    // property getter
    function getter() {
        return _val;
    };

    // property setter
    function setter( newVal ) {

        if ( _val != newVal ) {
            console.log( `Setting ${key} from ${_val} to ${newVal}` );
            _val = newVal;
            this._dirty = true;
        }
    };

    //
    // Delete original property and define new property with getter & setter
    //
    if ( delete this[key] ) {

        // Create new property with getter and setter
        Object.defineProperty( target, key, {
            get: getter,
            set: setter,
            enumerable: true,
            configurable: true
        });
    }
}

测试类

export class TestClass {

    private _dirty: boolean;

    @testProperty
    public propNum: number = 0;


    constructor() {
        this._dirty = false;
    }

    public copyFrom( tc: TestClass ) {
        this.propNum = tc.propNum;
    }
}

测试代码

describe( 'Copy Class Test', () => {

    it( 'Copy Test', () => {

        var t1 = new TestClass();
        var t2 = new TestClass();

        t2.propNum = 123;

        console.log( `t1.propNum = ${t1.propNum}` );
        console.log( `t2.propNum = ${t2.propNum}` );

        expect( t1.propNum ).toBe( 0 );

        t1.copyFrom( t2 );

        expect( t1.propNum ).toBe( 123 );
    });
});

最佳答案

这里的主要问题是 getter 和 setter 共享同一个变量,而不是根据实例获取值。

基本上和这样做是一样的:

function TestClass() {
}

var value;

Object.defineProperty(TestClass.prototype, "propNum", {
    get: function() { return value; },
    set: function(val) { value = val },
    enumerable: true,
    configurable: true
});

导致这种情况发生的原因:

var a = new TestClass(), b = new TestClass();
a.propNum = 2;
a.propNum === b.propNum; // true, because they're both referencing the same variable

第二个问题是 this[key] 引用了全局对象的一个​​属性。

您可能想要做的是这些方面的事情(未经测试的代码):

function testProperty( target: Object, key: string ) {
    const privateKey = "_" + key;

    function getter() {
        return this[privateKey];
    }

    function setter( newVal: any ) {
        if ( this[privateKey] != newVal ) {
            console.log( `Setting ${key} from ${this[privateKey]} to ${newVal}` );
            this[privateKey] = newVal;
            this._dirty = true;
        }
    }

    Object.defineProperty( target, key, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true
    });
}

关于javascript - 带有属性装饰器的 TypeScript 类就像静态的一样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35493375/

相关文章:

c# - 获取列表中的属性名称

c# - 如何从 Razor 切换到普通的旧 HTML?

javascript - 使用 html 按钮运行 python 脚本

javascript如何获取对象属性

angular - 找不到模块 '@angular/core/src/metadata/lifecycle_hooks' - primeng/table/table.d.ts

typescript - IntelliJ 实时模板。删除或替换文件名开头的数字

jquery - React 和 TypeScript - 如何在不包装在父 div 中的情况下进行渲染?

来自 C# winform 的 javascript on web 值

javascript - 在网站上无限滚动的图像裁剪

python - 使用动态创建的函数动态添加属性