skip to Main Content

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.

2

Answers


  1. 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);
    Login or Signup to reply.
  2. I would suggest to refactor this into multiple separate classes, but if you insist on nesting…

    I would like to keep the constructor free of these definitions.

    You can also place them in some other method and just call that from your constructor. Or you can even create the objects using methods:

    class DataController {
      // class fields
      id = 12;
      a = 10;
      b = 20;
      log = this._createLog();
      update = this._createUpdate();
    
      _createLog() {
        const self = this;
        return {
          entry: {
            get a() {
              return {
                id: self.id,
                value: self.a,
                label: 'a',
              };
            },
            get b() {
              return {
                id: self.id,
                value: self.b,
                label: 'b',
              };
            },
          }
        };
      }
      _createUpdate() {
        const self = this;
        return {
          set a(value) {
            self.a = value;
          },
          set b(value) {
            self.b = value;
          },
        };
      }
    }
    // class usage
    const data = new DataController();
    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);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search