I have read quite a few posts on JavaScript inheritance. They all seem quite involved, and some are very complicated to implement. I took a crack at it, and this is what I came up with.
Here are a few advantages to this simple JavaScript inheritance:
- Simple 🙂
- Use the same pattern to instantiate new objects.
- Supports “private” variables, functions
- Supports “public” (“privileged”) variables, functions
- Support “abstract” functions (sort of)
Methodology. All I’m doing is combining objects. I wrote an “extend” method that recursively combines objects together, and use it to combine the “this” variable inside a function with another object.
First thing, include this function somewhere in your code. This is the the secret sauce, the thing that makes it all possible (There’s actually nothing special about this method. You can use pretty much any “extend” method you like, like jQuery.):
function Extend(a) { if(typeof a != 'object') return false; function appendRecursively(a, b) { if(typeof a != 'object' || typeof b != 'object') return false; for(var i in b) { if(appendRecursively(a[i], b[i])) continue; a[i] = b[i]; } return true; } for(var i in arguments) { if(i == 0) continue; appendRecursively(a, arguments[i]); } return a; }
I can’t think of a better way to describe it than show you some code. Pay particular attention to the calls to “Extend” method. (See it on jsfiddle)
var Parent = function(o) { var self = this; // jump scope this.publicVariable = 'P publicVariable'; // public (privileged) variable var privateVariable = 'P privateVariable'; // private variable this.publicMethod = function() { output(self.publicVariable); // has access to public variables, methods output(privateVariable); // has access to private variables privateMethod(); // has access to private methods } this.getPrivateVariable = function() { return privateVariable; } var privateMethod = function() { output(self.publicVariable, privateVariable); // has access to public, private variables, methods. } this.abstractMethod = function() { // this is the closest thing JavaScript has to an abstract method throw 'abstractMethod() is not defined'; } Extend(this, o); // simple instantiation return this; } // ** this is all you really need for inheritance. var Child = function(o) { var child = new Parent(Extend(this, o)); // simple inheritance return child; } var GrandChild = function(o) { this.helloWorld = function(name) { return 'Hello, '+name+'.'; } var grandChild = new Child(Extend(this, o)); // simple inheritance return grandChild; } var GreatGrandChild = function(o) { this.publicVariable = 'GGC publicVariable'; // override the variable set in Parent this.publicMethod = function() { return privateMethod(); } var privateMethod = function() { return 'GGC privateMethod'; } this.abstractMethod = function() { return 'GGC Abstract Method'; } var greatGrandChild = new GrandChild(Extend(this, o)); // simple inheritance output(greatGrandChild.getPrivateVariable()); // has access to all parent's public methods, variables output(greatGrandChild.helloWorld('Great Grand Child')); return greatGrandChild; } output('_PARENT_'); var P = new Parent(); P.publicMethod(); output('_GRAND CHILD_'); var GC = new GrandChild({ publicMethod: function() { return 'GC publicMethod'; }, abstractMethod: function() { return 'GC Abstract Method'; } }); output(GC.publicMethod()); output(GC.abstractMethod()); output('_GREAT GRAND CHILD_'); var GGC = new GreatGrandChild(); output(GGC.publicMethod()); output(GGC.abstractMethod()); // ** this is how you could use this inheritance model for simple object instantiation. var InstantiatedObject = new Parent({ abstractMethod: function() { return 'GC Abstract Method'; } }); function output(str) { console.log(str); } /* Console Output: _PARENT_ P publicVariable P privateVariable P publicVariable P privateVariable _GRAND CHILD_ GC publicMethod GC Abstract Method _GREAT GRAND CHILD_ P privateVariable Hello, Great Grand Child. GGC privateMethod GGC Abstract Method */
(See it on jsfiddle)
Don’t like the way I did it? That’s okay. Here are a handful of other ways:
- http://ejohn.org/blog/simple-javascript-inheritance/
- http://www.crockford.com/javascript/inheritance.html
- http://stackoverflow.com/questions/7486825/javascript-inheritance
- http://weblogs.asp.net/dwahlin/archive/2011/08/03/techniques-strategies-and-patterns-for-structuring-javascript-code-revealing-prototype-pattern.aspx
- https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Inheritance_Revisited
- https://github.com/ded/klass
- https://github.com/Gozala/selfish