Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Extend class without inheriting, something like an "include" functionality of sorts #9

Open
darkguy2008 opened this Issue · 6 comments

2 participants

@darkguy2008

Hey!

I've chosen this library over a lot of others I've seen due to its ease of use and functionality. However, I'm in need of something that I bet it would make this even more powerful without getting bloaty (like the rest of class libs):

Let's say I have a class:

var myParent = Class.extend({
func1: function() { ... }
func2: function() { ... }
})

And it's getting long and long and longer. Let's "split" it in another .js file, doing something like:

myParent.extendEvenMore({
func3: function() { ... }
func4: function() { ... }
})

So, one could do:

myParent.func1(); myParent.func2(); myParent.func3(); myParent.func4();

I wonder if it's possible, or do you have a theory on how to do it so I can attempt to fork & code it?

Thanks again for this awesome lib!

@rowanmanning
Owner

Hi José, yes I like this idea. It's definitely achievable, the API would have to change, but it's just a case of adding all the methods defined in extendEvenMore to the class prototype. The API would have to look more like this:

var MyClass = Class.extend({
    func1: function() { ... }
    func2: function() { ... }
});

MyClass.reopen({
    func3: function() { ... }
    func4: function() { ... }
});

Currently this is possible without the reopen method by simply extending the prototype of your new class like so:

var MyClass = Class.extend({
    func1: function() { ... }
    func2: function() { ... }
});

MyClass.prototype.func3 = function() { ... };
MyClass.prototype.func4 = function() { ... };
@darkguy2008

Well, first of all thanks for your reply!

Your prototype suggestion was actually very helpful. It light a bulb about a hour ago and I managed to do it (I think :P). According to my quick tests, the code seems OK. Here it is! I know this might sound annoying, but if you could please check it, I'd be really glad and shall make a pull request if possible :).

Just add this method to chic.js:

    Class.reopen = function(props) {
        var Parent = this;
        var extendingFlag = '*extending*';
        var proto;

        // Extension
        Parent[extendingFlag] = true;
        proto = new Parent();
        delete Parent[extendingFlag];

        // Add new properties
        forEachProp(props, function (value, name) {
            if (isFn(value)) {
                Object.getPrototypeOf(proto)[name] = applySuperMethod(value, Parent.prototype[name]);
                return;
            }            
            Object.getPrototypeOf(proto)[name] = value;
        });

        // Construct
        function Class () {
            if (!Class[extendingFlag] && isFn(proto.init)) {
                proto.init.apply(this, arguments);
            }
        }

        // Add extend method and return
        Class.prototype = proto;
        Class.prototype.constructor = Class;
        Class.extend = Parent.extend;
        Class.reopen = Parent.reopen;
        return Class;
    };

And also add "Class.reopen = Parent.reopen;" to the Class.extend constructor so you can apply the reopen function, of course.

Sample app :)

var Class = chic.Class;

var MyClass = Class.extend({ 
    init: function() {
        this.lulz = false;
        console.log("OMG, lulz?", this.lulz);
    }
});

MyClass.reopen({
    omg: function() {
        this.lulz = true;
        console.log("Extended OMG!. Lulz? ", this.lulz);
    }
});

function Game() {
    var omg = new MyClass();
    omg.omg();
}

This outputs:
20:52:03.322 "OMG, lulz?" false game.js:6
20:52:03.322 "Extended OMG!. Lulz? " true game.js:13

So yay! :D

@rowanmanning

Cool, thanks José, this seems to work. If you decide to open a pull-request, I'd be a little concerned with the repetition between Class.extend and Class.reopen, I'm sure we could somehow abstract the code away and cut down on number of lines. Let me know if you're intending on doing this, otherwise I'm happy to do it when I get some spare time.

@darkguy2008 darkguy2008 referenced this issue from a commit in darkguy2008/chic
@darkguy2008 darkguy2008 Added "partial class" functionality
This change allows to extend a chic class with more functions or
properties, without inheriting. Very similar to what a mixin would do,
or what a partial class in C# means. This means, for example, that you
can add funcs/props to a class in separate .js files. This is related to
issue #9 -> rowanmanning#9

A line can be saved by replacing "applySuper" with its value instead,
but it is left as is for better code comprehension.
fc1b322
@darkguy2008

Alright Rowan, you were right. The change was actually very tiny, so I managed to do it using a simple conditional in the same extend method. The Class.extend method now can be used to create a new class ( var omg = Class.extend({}); ) or to add new stuff to it ( omg.extend({ }); ).

IMHO it can be a bit confusing at first, but hey, the change is only 3 lines and two variables!

I'd be glad if you can merge this into your main code. I used this change against my game library (which is about 15+ js files with almost half of it being classes extended with my method) without any problems whatsoever, the functionality was kept intact, I only had to change ".reopen" to ".extend" and voilá. :)

If there's anything else, let me know! :D

@rowanmanning

Hi José, I'm busy for the next couple of days but I'll try to take a look at this later in the week. Thanks

@darkguy2008

It's okay, I understand :). Also, submitted a quick fix, now it seems to build correctly in Travis :D. You're welcome! :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.