Created
January 8, 2013 08:53
-
-
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 …
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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