0
\$\begingroup\$

I've read a lot of stuff about mixins, inheritance and such, and in the end I came up with this solution for extending a class with multiple mixins. I haven't seen this anywhere else...

var Classes = {}; // I keep all classes inside this objects, so I can do new Classes[obj_name]();
Classes.asA = function () {
    var _init = this.init; // keep a copy of the previously declared method, if any
    this.init = function (a) {
        if (_init) _init.call(this, a); // call super method, if any
        this.a = a; // declare additional properties here
    }
    this.methodA = function () {
        console.log("a: "+this.a);
    }
}
Classes.asB = function () {
    var _init = this.init;
    this.init = function (a) {
        if (_init) _init.call(this, a);
        this.b = a+1;
    }
    this.methodB = function () {
        console.log("b: "+this.b);
    }
}
Classes.Obj = function () {
    var _init = this.init;
    this.init = function (a) {
        if (_init) _init.call(this, a);
        this.z = a-2;
    }
    this.methodZ = function () {
        console.log("z: "+this.z);
    }
}
Classes.asA.call(Classes.Obj.prototype); // extend Obj with asA
Classes.asB.call(Classes.Obj.prototype); // extend Obj with asB

var obj = new Classes.Obj();
obj.init(7); // will call in order asA.init, asB.init, Obj.init
obj.methodA(); // outputs "a: 7"
obj.methodB(); // outputs "b: 8"
obj.methodZ(); // outputs "z: 5"

Is this a good method? Do you see any problems with it?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Seems like it requires a lot of repetition in the constructor of the object and I think lines like Classes.asA.call(Classes.Obj.prototype); would be a bit confusing to see inside a code base. What problems were you trying to solve that popular methods did not resolve? \$\endgroup\$
    – GillesC
    Commented Jun 9, 2014 at 9:30
  • \$\begingroup\$ I need classes that inherit methods and properties from multiple classes, while being able to call the super functions when overwriting them, in the correct order. I thought that with this method it wouldn't repeat too much code except the init method (the constructor), since the rest is in the prototype and should be only created once when defining the classes. Is that correct? As for the Classes.asA.call(Classes.Obj.prototype); line, I've created a function that given multiple names, extends the original class, like Classes.extend("Obj","asA","asB"); \$\endgroup\$
    – gionatan
    Commented Jun 9, 2014 at 10:14

1 Answer 1

2
\$\begingroup\$

The main things is that your system is much more verbose and harder to understand than simply hard-coding all the calls to superclass methods:

function A(a) {
    this.a = a;
}
A.prototype = {
    methodA: function () {
        console.log("a: "+this.a);
    }
};

function B(a) {
    this.b = a+1;
}
B.prototype = {
    methodB: function () {
        console.log("b: "+this.b);
    }
};

function Obj(a) {
    A.call(this, a);
    B.call(this, a);
    this.z = a-2;
}
// Using underscore.js extend() to mix in methods from A and B
Obj.prototype = _({
    methodZ: function () {
        console.log("z: "+this.z);
    }
}).extend(A.prototype, B.prototype);

var o = new Obj(7);
o.methodA();
o.methodB();
o.methodZ();

Instead you should have some sort of factory method that creates new classes for you, setting up the mixins behind the scenes. For example:

var Foo = createClass({
    mixins: [ClassA, ClassB],
    someMethod: function() { ... }
});

I suggest you study some existing libraries that implement their own JavaScript class systems. There are lots of nuances of the JS object model that you need to be aware of. I strongly suggest you don't use your own home-grown class-system for production, but instead adopt some already bettle-tested implementation. But writing you own is a good way to learn more deeply about JavaScript.

\$\endgroup\$
2
  • \$\begingroup\$ The problem with this approach is that it doesn't allow me to extend the Obj class after it's been declared. I'd like to reuse the same js and add another js to extend the functionalities (viewer and editor, as explained in the updated post). Could you explain the factory method that creates classes or point me to some examples, please? It seems interesting. Yes, writing my own code is helping me learn js better, but I'd be happy to use an existing library if I can achieve the same result. Thanks! \$\endgroup\$
    – gionatan
    Commented Jun 9, 2014 at 14:00
  • \$\begingroup\$ You could look at MooTools as an example: mootools.net/docs/core/Class/Class \$\endgroup\$ Commented Jun 9, 2014 at 15:49

Not the answer you're looking for? Browse other questions tagged or ask your own question.