Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to assign the same constructor to many classes, while maintaining access to their defined fields?

Tags:

javascript

A pet peeve of mine in programming languages is taking the arguments passed in a constructor, and assigning them directly to fields in a class, named the same thing as the arguments I gave them in the constructor, like so:

class A {
    constructor(a, b) {
        this.a = a;
        this.b = b;
        etc...
    }
}

In order to get around this, I figured out I could create a function that took the existing keys in a class, and the arguments to them dynamically, like so:

function test(values) {
      Object.keys(this).map((x,i) => this[x] = values[i]);
}

class ChildObj {
      a1;
      a2;
      constructor() {
          test.call(this, arguments);
      }
}

This works perfectly, however, I would like to make it even more convenient by eliminating the repeated constructor declaration, as in my application I have many classes declared like this, and the same repeated 3 lines has begun to represent a significant chunk of the source code.

My first instinct was to use inheritance, however the fields are a property of the child object, and thus invisible to the parent. Then I tried to modify the class's constructor, which paired with an array of all the relevant classes could be done dynamically, however changing a class's constructor does not seem to be possible, as I tried

A.constructor = function() {
    test.call(this, arguments);
}

A.prototype.constructor = function() {
    test.call(this, arguments);
}

Temporarily, I pivoted to trying to define my object as a function, but that ran into the problem of accessing the names of the function parameters, and that's apparently only possible via Regexing the source code, which I'd rather avoid.

-----PS:-------

I have made somewhat of a breakthrough, managing to pass the child keys to the parent, by having the parent construct a copy of the child, but truncate the recursion there, like so:

class ParentObj {
    constructor() {
        if(ParentObj.constructor.in) {
            return;
        }
        ParentObj.constructor.in = true;
        let keys = Object.keys(new this.constructor);
        ParentObj.constructor.in = false;
        Object.keys(this).map((x,i) => this[x] = arguments[i]);
   }
}


class ChildObj extends ParentObj {
    a1
    a2
}

console.log(new ChildObj(3, 2));

However, it appears something else has broken, because it still does not assign the values to the resulting object.

-----END PS ---------

So, to conclude: Is it possible in Javascript to assign a constructor like this dynamically, and if not, is there another way of creating objects with trivial constructors like this? Thank you.

like image 650
James C Avatar asked Nov 07 '22 09:11

James C


1 Answers

No, this is not possible.

Those class fields are causing properties to get created in the constructor of the class, regardless whether it is an implicit one or whether you declared it explicitly. The parent constructor will never be able to access them, as you figured. Your best bet would be to use a decorator on the whole class, although for ES6 classes it's not exactly trivial.

The alternative would be to stop using class syntax, and just create your classes dynamically:

function makeClass(properties) {
    return function Class(...args) {
        for (const [i, p] of properties.entries())
            this[p] = args[i];
    };
}

const A = makeClass(["a1", "a2"]);
like image 127
Bergi Avatar answered Nov 14 '22 21:11

Bergi