8

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

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交互触发。

4

4 回答 4

15

您可以添加一个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"}"

于 2016-11-03T17:29:38.763 回答
5

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

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% 相同。事实上,这就是为什么使用下划线格式如此普遍的原因。下划线告诉任何查看代码的人该属性是“私有的”。在 ECMAScript 6 中,私有成员的概念并不真正存在。

于 2016-11-03T17:27:24.633 回答
2

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

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')))

于 2016-11-03T17:33:29.997 回答
0

正如您所说,您想避免toJSON在每个课程中使用(但我也认为使用toJSON是“正确”的做法)。

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, '"$1":');
    },
    parse: function(str) {
      return originalJSON.parse(str.replace(/"(\w+)":/g, '"_$1":'));
    }
  };

  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' }
于 2016-11-04T14:22:27.660 回答