Skip to content

Instantly share code, notes, and snippets.

@geddski
Created January 8, 2013 08:53
Show Gist options
  • Save geddski/4482278 to your computer and use it in GitHub Desktop.
Save geddski/4482278 to your computer and use it in GitHub Desktop.
Pattern for Object Oriented JavaScript. You can run these tests with Mocha and play around with it. You'll need node installed, and then install should (locally) and mocha (globally): 1. download oo-pattern.js somewhere (~/js for example) 2. $cd ~/js 3. npm install should 4. $npm install -g mocha 5. mocha oo-pattern.js NOTE: I think inheritance …
/* Pattern for OOP in JavaScript */
//TODO see if safe way to add inheritsFrom to Function
var should = require('should');
function inherit(C, P){
var F = function(){}; //intermediary function between Parent and Child
F.prototype = P.prototype; //link intermediary function to Parent
var funcs = C.prototype; //keep track of any existing functions on the Child prototype
C.prototype = new F(); //link child to intermediary function
for (var attrname in funcs) {
C.prototype[attrname] = funcs[attrname]; //restore functions to Child's prototype
}
C._super = P.prototype; //store access to the parent ("super" is a reserved word in JS)
C._superConstructor = P; //store access to the parent constructor
C.prototype.constructor = C; //optinally reset the constructor property to Child so that instance.constructor will be Child and not Parent.
}
describe('Child', function(){
var Parent, Child;
beforeEach(function(){
//Parent Constructor
Parent = function(name){
this.name = "Pappa " + name;
this.awesome = true;
};
Parent.prototype.sayHello = function(){
return 'hola ' + this.name;
};
Parent.prototype.speak = function(msg){
return msg;
};
//Child Constructor
Child = function(name){
this.name = name;
this.spoiled = true;
/* IMPORTANT: Child should invoke its Parent constructor, keeping
the child instance as "this" */
Child._superConstructor.apply(this, arguments);
};
Child.prototype.speak = function(msg){
//override a super method but still use it
return '<sarcasm> ' + Child._super.speak(msg) + ' </sarcasm>';
};
//link them so that Child inherits from Parent
inherit(Child, Parent);
});
it('should inherit functionality from Parent', function(){
//create instance
var child = new Child("Stevo");
//the instance object has been 'augmented' by the Parent constructor function
child.awesome.should.equal(true);
child.name.should.equal('Pappa Stevo');
//the instance now has access to functions on the Parent
should.exist(child.sayHello);
child.sayHello().should.equal('hola Pappa Stevo');
//Child used "_super" to extend a method
child.speak('this is fun').should.equal('<sarcasm> this is fun </sarcasm>');
});
describe('the prototype chain', function(){
it('links objects to objects via __proto__', function(){
/*
NOTE: __proto__ is nonstandard and should never be used directly,
it just helps to use it to visualize the prototype chain.
These four OBJECTS are linked:
instance object --> Child.prototype --> Parent.prototype --> Object.prototype
So that when a method is called on the instance, the JS engine will first
check the instance for that method. If it has it, it will execute it. If not,
it will check the next object up in the chain (Child.prototype) and so on, all
the way up the chain to the highest level object (Object.prototype).
*/
//Parent.prototype (object) linked to Object.prototype (object)
Parent.prototype.__proto__.should.equal(Object.prototype);
//Child.prototype (object) linked to Parent.prototype (object)
Child.prototype.__proto__.should.equal(Parent.prototype);
//an instance (object) is linked to its Constructor's prototype (object)
var child = new Child('Stevo');
child.__proto__.should.equal(Child.prototype);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment