The Class patterns i've seen around pretty much es to something like this:
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'))
execution output:
Foo { _x: 'x', _y: 'y', _z: 'z' }
console.log(JSON.stringify(new Foo('x', 'y', 'z')))
execution output:
{"_x":"x","_y":"y","_z":"z"}
Which gives me underscore prefixed fields, and i wasnt aiming for that, how can i get the fields to have no underscore prefix, and yet, having getters and setters triggered by instance.prop
interaction.
The Class patterns i've seen around pretty much es to something like this:
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'))
execution output:
Foo { _x: 'x', _y: 'y', _z: 'z' }
console.log(JSON.stringify(new Foo('x', 'y', 'z')))
execution output:
{"_x":"x","_y":"y","_z":"z"}
Which gives me underscore prefixed fields, and i wasnt aiming for that, how can i get the fields to have no underscore prefix, and yet, having getters and setters triggered by instance.prop
interaction.
-
I would say to remove the _ from behind the variables? like
constructor(x, y, z) { this.x = x; this.y = y; this.z = z; }
– Orelsanpls Commented Nov 3, 2016 at 17:14 - 1 Yeah, in this example there is zero advantage over just assigning the properties directly and skipping the getter. – loganfsmyth Commented Nov 3, 2016 at 17:52
-
@loganfsmyth Sorry for the poor example, but im acctually using custom setter for properties in my
real world application
, ill edit my snippet for better prehension. – vcorrea Commented Nov 3, 2016 at 18:42 -
What are you doing with this JSON data after? I'd say generally you shouldn't rely on JSON auto-serialization of a class, if something is a class, you should have a method, either explicitly or via
.toJSON
for getting a serializable object version of it. – loganfsmyth Commented Nov 3, 2016 at 18:56 -
@loganfsmyth for now, im just persisting the data on mongodb with the native driver (which is saving the properties with underscore), and returning it in exposed JSON API (in this case, i use
.toJSON
only for classes i want to ommit fields i dont want to end up in front-ends, like passwords). – vcorrea Commented Nov 3, 2016 at 19:04
4 Answers
Reset to default 15You can add a toJSON
method to adjust the output of 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));
outputs: "{"x":"x","y":"y","z":"z"}"
If your problem really is only the underscores, then you could try using a naming convention more similar to C#'s properties where the get/set methods are using PascalCase but the member variables use camelCase, like so:
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;
}
}
Ultimately, due to how objects work in ECMAScript 6 there is no way to have both the member variable and get/set methods named 100% the same. In point of fact, this is why using the underscore format is so mon. The underscore tells anyone looking at the code that the property is intended to be "private". In ECMAScript 6, the concept of private members doesn't really exist.
If you want to skip the underscore properties, define them as non-enumerable:
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')))
You can also consider symbols instead of underscored properties:
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')))
As you said you wanted to avoid using toJSON
in every class (but I also think using toJSON
is the "right" thing to do).
Javascript let you do weird things, but at least you can control it in an enclosed function scope.
I guess the regex could be refined but I just wanted to show the idea, not pretty but should work.
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));
Output:
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' }