Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript inherance and use of super: is this possible?

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {
        }

        F.prototype = o;
        var f = new F();

        if(f.init){
            f.init();
        };

        return f;
    };
}

var inherit = function(P, C) {
    var i;
    for(i in P) {
        // if is the current parent
        if(P.hasOwnProperty(i) === false) {
            continue;
        };

        // define the uper property
        C.uper = {};

        // methods
        if(typeof P[i] === 'function') {
            // set as super
            C.uper[i] = P[i];
            // if child already defined, skip
            if(typeof C[i] === 'function') {
                continue;
            };
            C[i] = P[i];
        }

        // properties 
        else {
            // if child already defined a property, skip
            if(!(typeof C[i] === 'undefined')) {
                continue;
            };
            C[i] = P[i];
        }
    }
    return C;
}


var Parent1 = (function(){
    var that = {};

    // private var
    var _name = 'Parent1';

    // public var
    that.lastName = 'LastName';

    // public method
    that.getName = function(){
        // if this.uper.getName.call(this)
        return _name + this.lastName;
        // else
        // return _name + that.lastName;
    }

    // return the literal object
    return that;
}());

var Parent2 = {
    // fake private var
    _name: 'Parent2',

    // public method
    getName: function(){
        // as we call this method with the call method
        // we can use this
        return this._name;
    }
}

var Child1 = inherit(Parent1, (function(){
    var that = {};

    // overriden public method
    that.getName = function(){
        // how to call the this.uper.getName() like this?
        return 'Child 1\'s name: ' + this.uper.getName.call(this);
    }

    that.init = function(){
        console.log('init');
    }

    // return the literal object
    return that;
}()));

var Child2 = inherit(Parent2, {
    getName: function(){
        // how to call the this.uper.getName() like this?
        return 'Child 2\'s name: ' + this.uper.getName.call(this);
    }
});

var child1 = Object.create(Child1);
// output: Child 1's name: Parent1LastName
console.log(child1.getName());

var child2 = Object.create(Child2);
// output: Child 2's name: Parent2
console.log(child2.getName());
// how to call the this.uper.getName() like this?

how to call the this.uper.getName() like this?

like image 301
Totty.js Avatar asked Jan 21 '23 20:01

Totty.js


2 Answers

Yes

Javascript uses Prototypal inheritance. So essentially objects inherit Objects (and everything is an Object)

Here are a couple links that should help get the point across.

  • Javascript Module Pattern
  • Module Pattern In-depth

Here's the basic module pattern:

var MODULE = (function (my) { 
    my.anotherMethod = function () { 
        // added method... 
    }; 

    return my; 
}(MODULE));

Then you can do something like this to mimic inheritance:

var MODULE_TWO = (function (old) { 
    var my = {}, 
        key; 

    for (key in old) { 
        if (old.hasOwnProperty(key)) { 
            my[key] = old[key]; 
        } 
    } 

    var super_moduleMethod = old.moduleMethod; 
    my.moduleMethod = function () { 
        // override method on the clone, access to super through super_moduleMethod 
    }; 

    return my; 
}(MODULE));

This style of coding takes a bit of getting used to, but I definitely prefer it to classical inheritance at this point. If this code isn't making sense, check out the Douglas Crockford lectures and it should clarify most of it.


addressing the edit: You can create different instantiations of these objects by using the new operator.

OR

I'd recommend using this little method which extends the Object Prototype (again if this doesn't make sense see the Douglas Crockford video). I forget the exact reasons why this is so heavily recommended by him, but at the very least it eliminates some confusion in that the new operator is a bit different than in classical languages. Needless to say using only using the new operator is insufficient.

What this function does is extends the Object prototype with a method create. It then...

  1. Defines function F in a contained namespace.
  2. Assigns the function F's prototype to the object that is passed
  3. returns the newly constructed Object.

(outlined better by douglas crockford himself in the prototypal inheritance link)

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
newObject = Object.create(oldObject);

So using your code...

var a = Object.create(MODULE_TWO),
var b = Object.create(MODULE_TWO);
like image 196
Derek Adair Avatar answered Jan 27 '23 23:01

Derek Adair


Answering based on your last edit, you could use something like this:

function Class(ctor, parent) {
    var c = Function.prototype.call;
    function clas() {

        // expose the parent as super
        this.super = parent;
        ctor.apply(this, arguments);
    }

    // save the constructor
    clas.constructor = ctor;

    // provide a static constructor
    clas.init = function() {
        c.apply(parent.constructor, arguments);
    };

    // Setup the prototype
    clas.prototype = parent ? parent.prototype : {};

    // provide an extend method
    clas.extend = function(methods) {
        for(var i in methods) {
            if (methods.hasOwnProperty(i)) {
                clas.prototype[i] = methods[i];
            }
        }
        return clas;
    };
    return clas;
}

Examples:

var Animal = Class(function(name) {
    this.name = name;
});

var Cat = Class(function(name) {
    this.super(name);

}, Animal).extend({
    meow: function() {
        console.log('Meow! My name is ' + this.name + '.');
    }
});

new Cat('Neko').meow();

There are at least a trillion different ways to implement "Classes" in JavaScript, the more you want to hide the internals the more "magical" the code becomes, the above is very simple though.

You can (and probably need) customize this to fit your needs. But always keep in mind that there might be situations where a full blown Class emulation approach might not be the best one.

I already posted it as a comment, but in case you want to have everything hidden away for you, I've written a pretty feature rich, but still fast, Class library my own:
https://github.com/BonsaiDen/neko.js

like image 25
Ivo Wetzel Avatar answered Jan 27 '23 23:01

Ivo Wetzel