ECMAScript 6 Class 属性下划线前缀

ECMAScript 6 Class properties underscore prefix

我见过的 Class 模式几乎都是这样的:

class Foo {
    constructor(x, y, z) {
      this._x = x;
      this._y = y;
      this._z = z;
    }

    get x() {
      return this._x;
    }
    set x(value) {
      //I acctually do some stuff here
      this._x = value;
    }

    get y() {
      return this._y;
    }
    set y(value) {
      //I acctually do some stuff here
      this._y = value;
    }

    get z() {
      return this._z;
    }
    set z(value) {
      //I acctually do some stuff here
      this._z = value;
    }
}

console.log(new Foo('x', 'y', 'z'))执行输出:

Foo { _x: 'x', _y: 'y', _z: 'z' }

console.log(JSON.stringify(new Foo('x', 'y', 'z')))执行输出:

{"_x":"x","_y":"y","_z":"z"}

这给了我带下划线前缀的字段,而我并不是为了那个,我怎样才能让这些字段没有下划线前缀,并且让 getter 和 setter 由 instance.prop 交互触发。

如果您的问题确实只是下划线,那么您可以尝试使用更类似于 C# 属性的命名约定,其中 get/set 方法使用 PascalCase,但成员变量使用驼峰式命名,如下所示:

class Foo {
    constructor(x, y, z) {
      this.x = x;
      this.y = y;
      this.z = z;
    }

    get X() {
      return this.x;
    }
    set X(value) {
      this.x = value;
    }

    get Y() {
      return this.y;
    }
    set Y(value) {
      this.y = value;
    }

    get Z() {
      return this.z;
    }
    set Z(value) {
      this.z = value;
    }
}

最终,由于对象在 ECMAScript 6 中的工作方式,无法使成员变量和 get/set 方法的命名 100% 相同。事实上,这就是使用下划线格式如此普遍的原因。下划线告诉任何查看代码的人 属性 应该是 "private"。在 ECMAScript 6 中,私有成员的概念并不真正存在。

您可以添加一个toJSON方法来调整JSON.stringify

的输出
class Foo {
    constructor(x, y, z) {
      this._x = x;
      this._y = y;
      this._z = z;
    }

    get x() {
      return this._x;
    }
    set x(value) {
      this._x = value;
    }

    get y() {
      return this._y;
    }
    set y(value) {
      this._y = value;
    }

    get z() {
      return this._z;
    }
    set z(value) {
      this._z = value;
    }

    toJSON() {
      return {
        x: this._x,
        y: this._y,
        z: this._z
      };
    }
}

var foo = new Foo('x', 'y', 'z');
console.log(JSON.stringify(foo));

输出:"{"x":"x","y":"y","z":"z"}"

如果要跳过下划线属性,将它们定义为不可枚举:

class Foo {
  constructor(x, y, z) {
    this._x = x;
    this._y = y;
    this._z = z;
    Object.defineProperties(this, {
      _x: {enumerable: false},
      _y: {enumerable: false},
      _z: {enumerable: false}
    });
  }
  get x() { return this._x; }
  set x(value) { this._x = value; }
  get y() { return this._y; }
  set y(value) { this._y = value; }
  get z() { return this._z; }
  set z(value) { this._z = value; }
}
console.log(JSON.stringify(new Foo('x', 'y', 'z')))

你也可以考虑符号而不是下划线属性:

class Foo {
  constructor(x, y, z) {
    this[Foo.x] = x;
    this[Foo.y] = y;
    this[Foo.z] = z;
  }
  get x() { return this[Foo.x];  }
  set x(value) { this[Foo.x] = value; }
  get y() { return this[Foo.y]; }
  set y(value) { this[Foo.y] = value; }
  get z() { return this[Foo.z]; }
  set z(value) { this[Foo.z] = value; }
}
Foo.x = Symbol('x');
Foo.y = Symbol('y');
Foo.z = Symbol('z');
console.log(JSON.stringify(new Foo('x', 'y', 'z')))

正如您所说,您想避免在每个 class 中使用 toJSON(但我也认为使用 toJSON 是 "right" 要做的事情)。

Javascript让你做一些奇怪的事情,但至少你可以在封闭的函数范围内控制它。

我想正则表达式可以改进,但我只是想展示这个想法,虽然不漂亮但应该可以。

class Foo {
  constructor(x, y, z) {
    this._x = x;
    this._y = y;
    this._z = z;
  }

  get x() {
    return this._x;
  }
  set x(value) {
    //I acctually do some stuff here
    this._x = value;
  }

  get y() {
    return this._y;
  }
  set y(value) {
    //I acctually do some stuff here
    this._y = value;
  }

  get z() {
    return this._z;
  }
  set z(value) {
    //I acctually do some stuff here
    this._z = value;
  }
}

var originalJSON = JSON;

var foo = new Foo('x', 'y', 'z');

(function () {

  var JSON = {
    stringify: function (obj) {
      var json = originalJSON.stringify(obj);
      return json.replace(/"_+(\w+)":/g, '"":');
    },
    parse: function(str) {
      return originalJSON.parse(str.replace(/"(\w+)":/g, '"_":'));
    }
  };

  console.log('Weird hack');

  var r = JSON.stringify(foo);    
  console.log('stringify');
  console.log(r);

  console.log('parse');
  console.log(JSON.parse(r));
}).call();

console.log('\nBack to normal');

var r = JSON.stringify(foo);
console.log('stringify');
console.log(r);

console.log('parse');
console.log(JSON.parse(r));

输出:

Weird hack
stringify
{"x":"x","y":"y","z":"z"}
parse
{ _x: 'x', _y: 'y', _z: 'z' }
Back to normal
stringify
{"_x":"x","_y":"y","_z":"z"}
parse
{ _x: 'x', _y: 'y', _z: 'z' }