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

Javascript Convert Class Variable to Getter/Setter using Decorators

关于如何使用装饰器将 class 字段转换为 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 的初始值。

class 需要在存储值的地方保持私有 属性。

由于 class fields aren't currently supported 装饰器提议和较新的 transform-decorators Babel 插件,应改用较旧的 transform-decorators-legacy Babel 插件。

transform-decorators-legacy documentation 所建议的那样,为了为 属性、initializer 方法和 writable [= 提供 get/set 访问器46=] 应该从描述符对象中删除。由于 initializer 函数包含初始 class 字段值,因此应将其检索并分配给私有 属性:

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) 将分配给 class prototype 并且不会触发 set 访问器,而下一个值 (1) 将分配给 class 实例 并将触发 set 访问器。

由于 transform-decorators-legacy 不符合规范,这不适用于其他装饰器实现,例如TypeScript 和装饰器提案。

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

class Foo {
  get bar() { return this._bar };
  set bar(val) { this._bar = val };
}

Foo.prototype._bar = 0;