Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing instance methods/variables in prototypal inheritance

Tags:

javascript

I've been playing around with prototypal inheritance after reading http://javascript.crockford.com/prototypal.html and having a bit of a problem with understanding how I could make use of it in the way I would use classical inheritance. Namely, all functions and variables inherited by the prototype essentially become statics unless they are overwritten by the child object. Consider this snippet:

var Depot = {   
    stockpile : [],
    loadAmmo : function (ammoType) {
        this.stockpile.push(ammoType);
    }
};

var MissileDepot = Object.create(Depot);
var GunDepot = Object.create(Depot);

stockpile and loadAmmo definitely should be in the prototype, since both MissileDepot and GunDepot have them. Then we run:

MissileDepot.loadAmmo("ICBM");
MissileDepot.loadAmmo("Photon Torpedo");

alert(MissileDepot.stockpile); // outputs "ICBM,Photon Torpedo"
alert(GunDepot.stockpile); // outputs "ICBM,Photon Torpedo"

This is expected because Neither MissileDepot nor GunDepot actually have stockpile or loadAmmo in their objects, so javascript looks up the inheritance chain to their common ancestor.

Of course I could set GunDepot's stockpile manually and as expected, the interpreter no longer needs to look up the chain

GunDepot.stockpile = ["Super Nailgun", "Boomstick"];
alert(GunDepot.stockpile); // outputs "Super Nailgun,Boomstick"

But this is not what I want. If this were classical inheritance (say Java), loadAmmo would operate on MissileDepot and GunDepot's stockpile independently, as an instance method and an instance variable. I would like my prototype to declare stuff that's common to children, not shared by them.

So perhaps I'm completely misunderstanding the design principles behind prototypal inheritance, but I'm at a loss as how to achieve what I've just described. Any tips? Thanks in advance!

like image 485
ambertch Avatar asked Jan 21 '10 08:01

ambertch


2 Answers

Javascript provides a way to do this the way U are used to :) try this:

function Depot() {   
    this.stockpile = [],
    this.loadAmmo = function (ammoType) {
        this.stockpile.push(ammoType);
    }
};

var MissileDepot = new Depot();
var GunDepot = new Depot();


MissileDepot.loadAmmo("ICBM");
MissileDepot.loadAmmo("Photon Torpedo");

alert(MissileDepot.stockpile); // outputs "ICBM,Photon Torpedo"
alert(GunDepot.stockpile); // outputs ""

And U can add the functions on the fly afterwards:

MissileDepot.blow = function(){alert('kaboom');}

Extending object with another object is also an option, but what You wanted is the fact, that OO programming in javascript is done by functions not objects with {} ;)

EDIT:

I feel bad for writing that without mentioning: The javascript "new" keyword is only for making it easier to OO veterans. Please, dig deeper into the prototypal inheritance and dynamic object creation as therein lies true magic! :)

like image 79
naugtur Avatar answered Sep 21 '22 06:09

naugtur


For the method, all works as expected. It's just the fields that you need to take care of.

What I see a lot in YUI, is that the constructor allocates the instance varialbes. 'Classes' that inherit from a parent call the constructor of their parent. Look here: http://developer.yahoo.com/yui/docs/DataSource.js.html

Example base class:

util.DataSourceBase = function(oLiveData, oConfigs) {
    ...   
    this.liveData = oLiveData;

    ... more initialization...
}

Example subclass:

util.FunctionDataSource = function(oLiveData, oConfigs) {
    this.dataType = DS.TYPE_JSFUNCTION;
    oLiveData = oLiveData || function() {};

    util.FunctionDataSource.superclass.constructor.call(this, oLiveData, oConfigs);   
};

// FunctionDataSource extends DataSourceBase
lang.extend(util.FunctionDataSource, util.DataSourceBase, {
    ...prototype of the subclass...
});
like image 36
Roland Bouman Avatar answered Sep 20 '22 06:09

Roland Bouman