The issue in question relates to human readability and data organization. I would like to assign getters and setters as children of class field properties, however I can't get this
to reference the class prototype data. I think this is the same problem solved by using self
in a class constructor, but applied to class fields instead. Is there a comparable solution for class fields that would keep these definitions out of the constructor?
This is the format I would like to achieve. The constructor is not invoked because external data is not required for these field definitions. This throws a recursion error.
class data_controller {
// class fields
id = 12;
a = 10;
b = 20;
// log data entries
log = {
entry: {
get a() {
return {
id: this.id,
value: this.a,
label: 'a',
};
},
get b() {
return {
id: this.id,
value: this.b,
label: 'b',
};
},
},
};
// update data
update = {
set a(value) {
this.a = value;
},
set b(value) {
this.b = value;
},
};
}
// class usage
const data = new data_controller();
console.log(data.log.entry.a);
console.log(data.log.entry.b);
data.update.a = 50;
data.update.b = 60;
console.log(data.log.entry.a);
console.log(data.log.entry.b);
This is the format using 'self' and the constructor. I would like to keep the constructor free of these definitions.
class data_controller {
// class fields
id = 12;
a = 10;
b = 20;
log = {};
update = {};
constructor() {
self = this;
// log data entries
this.log.entry = {
get a() {
return {
id: self.id,
value: self.a,
label: 'a',
};
},
get b() {
return {
id: self.id,
value: self.b,
label: 'b',
};
},
};
// update data
this.update = {
set a(value) {
self.a = value;
},
set b(value) {
self.b = value;
},
};
}
}
// class usage
const data = new data_controller();
console.log(data.log.entry.a);
console.log(data.log.entry.b);
data.update.a = 50;
data.update.b = 60;
console.log(data.log.entry.a);
console.log(data.log.entry.b);
This is a format which keeps the constructor free of definitions but does not implement the getter/setter class usage.
class data_controller {
// class fields
id = 12;
a = 10;
b = 20;
// log data entries
log = {
entry: {
a: () => {
return {
id: this.id,
value: this.a,
label: 'a',
};
},
b: () => {
return {
id: this.id,
value: this.b,
label: 'b',
};
},
},
};
// update data
update = {
a: (value) => {
this.a = value;
},
b: (value) => {
this.b = value;
},
};
}
// class usage
const data = new data_controller();
console.log(data.log.entry.a());
console.log(data.log.entry.b());
data.update.a(50);
data.update.b(60);
console.log(data.log.entry.a());
console.log(data.log.entry.b());
I believe I could also solve this issue by making the class field organization flat, but I would like to maintain multi-level structures.
You can add a reference to the containing object in the nested objects. It's parent
in the code below. Then you can use this.parent
to go up a level.
class data_controller {
// class fields
id = 12;
a = 10;
b = 20;
// log data entries
log = {
entry: {
parent: this,
get a() {
return {
id: this.parent.id,
value: this.parent.a,
label: 'a',
};
},
get b() {
return {
id: this.parent.id,
value: this.parent.b,
label: 'b',
};
},
},
};
// update data
update = {
parent: this,
set a(value) {
this.parent.a = value;
},
set b(value) {
this.parent.b = value;
},
};
}
// class usage
const data = new data_controller();
console.log(data.log.entry.a);
console.log(data.log.entry.b);
data.update.a = 50;
data.update.b = 60;
console.log(data.log.entry.a);
console.log(data.log.entry.b);