使用装饰器为实体属性生成通用getter和setter

时间:2015-07-04 19:47:55

标签: typescript

我正在将我的模型实体转换为Typescript(使用ajax调用填充它们)。我希望每个人都能为我的实体中的每个属性设置一个基本的getter和setter:

entity.setProductID("2r3e4r4t5y6t5y6") and entity.getProductID()

目前,我正在为类

中的每个属性定义这些方法
   /**
    *@name "productID"
    *@ormtype "string"
    *@length "32"
    *@fieldtype "id"
    *@generator "uuid"
    *@unsavedvalue ""
    */
    private productID: string;

    getProductID():string { return this.productID; }
    setProductID(productID:string) { this.productID = productID; }

但是我每个实体和150个实体大约有30到80个属性,因此代码对getter和setter定义有点冗长。

为了解决这个问题,我希望使用装饰器@generateGetterAndSetter,我可以用它来装饰每个属性,为我动态生成getter和setter。看起来像:

@generateGetterAndSetter
private productID: string;

为了实现这一点,我定义了装饰器并将其添加到我的模块中:

/** decorate the property to attach a getter and setter */
function generateGetterAndSetter(target: any, key: string) {

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

  // property getter
 var getMethodName = 'get' + key.charAt(0).toUpperCase() + key.slice(1);
 var setMethodName = 'set' + key.charAt(0).toUpperCase() + key.slice(1);

  /** Build the getter and setter functions dynamically */
  var getter = new Function("return function " + getMethodName + "(){  return _val;}")();
  var setter = new Function("return function " + setMethodName + "(newVal){  _val = newVal;}")();

  target[getMethodName] = getter;
  target[setMethodName] = setter;

  Object.defineProperty(target, key, {
      get: getter,
      set: setter,
      enumerable: true,
      configurable: true
  });
}//<--end generateGetterAndSetterDefinition

从上面的代码中,您可以看到我已经尝试过Object.defineProperty以及手动将函数添加到目标。但在测试中:

var product = new Product();
product.setProductID("123456789");  
product.setProductName("Generic Shoes");
product.setUrlTitle("http://some/brand/get");   

console.log("Product: ", product.getProductName(), product.getProductID(), product.getUrlTitle());

它会产生错误的结果:

Product: http://some/brand/get http://some/brand/get http://some/brand/get

而不是预期的

Product: Generic Shoes 123456789 http://some/brand/get

这肯定是因为我正在覆盖每个作业的定义。有没有更好的方法来解决这个问题,而不必为每个属性包含一个get / set方法,同时仍然保持getPropertyName()和setPropertyName(value)的正确函数命名约定?

2 个答案:

答案 0 :(得分:3)

如果您选中window._val,则会在运行代码后看到它等于http://some/brand/get。因此,所有函数都是从同一个变量读取和写入,因为var _valnew Function("...");的范围会丢失。

您应该只在对象的原型上定义函数 - target

function generateGetterAndSetter(target: Object, key: string) {
    var getMethodName = 'get' + key.charAt(0).toUpperCase() + key.slice(1);
    var setMethodName = 'set' + key.charAt(0).toUpperCase() + key.slice(1);

    target[getMethodName] = function() {
        return this[key];
    };
    target[setMethodName] = function(val) {
        this[key] = val;
    };
}

答案 1 :(得分:1)

我不知道ts。但是自从ES2015(又名&#34; ES6&#34;)规范以来,JavaScript现在具有proxies。代理允许您创建对象(外观)其他对象的真实代理。

var obj = new Proxy({}, {
get: function(target, name) {
    if (!(name in target)) {
        console.log("Getting non-existant property '" + name + "'");
        return undefined;
    }
    return target[name];
},
set: function(target, name, value) {
    if (!(name in target)) {
        console.log("Setting non-existant property '" + name + "', initial value: " + value);
    }
    target[name] = value;
    return true;
}
});

console.log("[before] obj.foo = " + obj.foo);
obj.foo = "bar";
console.log("[after] obj.foo = " + obj.foo);