Javascript使用装饰器将类变量转换为Getter / Setter

时间:2018-01-21 12:45:25

标签: javascript babeljs ecmascript-next

我是如何使用装饰器将类字段转换为getter / setter的?例如:

class Foo:
    @accessor bar = 0;

const foo = new Foo;

应该表现出自定义行为,例如foo.bar = 1;

我已经尝试了类似

的内容
function accessor(target, name, descriptor) {
    let val;

    return {
        set: function(newVal) {
            val = newVal;
            console.log("setter called");
        },
        get: function() { return val; }
    };
}

但是这会丢失bar = 0的初始值。

1 个答案:

答案 0 :(得分:2)

该类需要维护将存储值的私有属性。

由于装饰者提案class fields aren't currently supported以及较新的transform-decorators Babel插件,应使用较旧的transform-decorators-legacy Babel插件。

正如transform-decorators-legacy documentation所示,为了为属性提供get / set访问器,应该从描述符对象中删除initializer方法和writable属性。由于initializer函数包含初始类字段值,因此应检索它并将其分配给私有属性:

function accessor(classPrototype, prop, descriptor) {
  if (descriptor.initializer)
    classPrototype['_' + prop] = descriptor.initializer();

  delete descriptor.writable;
  delete descriptor.initializer;

  descriptor.get = function () { return this['_' + prop] };
  descriptor.set = function (val) { this['_' + prop] = val };
}

class Foo {
  @accessor bar = 0;
}

const foo = new Foo ;
foo.bar = 1;

由于其工作方式,初始值(0)将分配给类原型,并且不会触发set访问器,而下一个值({ {1}})将被分配到类实例,并将触发1访问者。

由于set不符合规范,因此这不适用于其他装饰器实现,例如: TypeScript和装饰提案。

上述代码的直接符合规范的ES6对应物是:

transform-decorators-legacy