Monday, February 25, 2013

JavaScript - Dynamic Prototyping

There are thousands of JavaScript prototype tutorials online

Okay, so most people know about and/or understand JavaScript's prototypical inheritance system. Every object has a prototype which is an object, and when you look for a property on that object, if it doesn't have it, it checks the prototype for the property, and if it doesn't have it, it checks prototype's prototype for the property, etc. etc. (If anyone really wants me to do an entry on this, let me know, but rest assured it's pretty well covered elsewhere)

First let me go over the plain, boring ways prototype is commonly used

(It gets better further down)

In practice, 99% of the time, JavaScript's prototype ends up getting used like this:

//create some class.
function Foo() {

//add some properties to it.
Foo.prototype.test = function () {
}; = 123;

//use it.
var foo = new Foo();
foo.test(); //alert wee
console.log(; //123

Boring. Boring. Boring.

Then occasionally you'll see some blog entry come along about "OOP in JS" or whatever and you'll see prototype getting used like so:

//create a class.
function Foo(){
Foo.prototype.test = 'wee';

//create another class.
function Bar() {
//that inherits from the first class.
Bar.prototype = new Foo();

//try it out.
var bar = new Bar();
console.log(bar.test); //wee

Okay, well that's a little more interesting, right? We've got some semblance of two class definitions where one inherits from the other. Pretty cool, I guess. Still not terribly exciting, though.

Dynamic Prototyping! (Finally something interesting)

I'm sure there's a better word for it, but I'm calling it "Dynamic Prototyping" (it's my blog!). JavaScript is dynamic and fun. Certainly we can do something cooler with this right? I mean, this seems like something we can really hack to our advantage. And then I saw what AngularJS was doing with prototypical inheritance. They were using it in a dynamic way, allowing "scopes" to inherit from one another, and changes to propagate from parent to child (but not child to parent). Check this out:

//create a class
function Foo(){ 

//Give it a method to create child clones of itself
Foo.prototype.spawnClone = function() {
    //Dynamically assign the current instance as a prototype.
    Foo.prototype = this;
    //return a new one
    return new Foo();

//Give it a try
var foo = new Foo(); = 'test';
var fooSpawn = foo.spawnClone();
alert(; //test

//so far, so good, but watch this: = 'weee';

//we actually updated the child by updating the parent!
alert(; //weee

Now that's cool! Now I can take an object, and create a "child object" that not only inherits its properties, but is actually bound to that object programmatically. Granted, it's a one way binding, but it's still a lot of fun.

Watch out! Prototypical Madness!

So, we learned that we can dynamically prototype a constructor function. That's pretty cool. But watch out! The class will use whatever prototype was assigned to it last!

See where we can run into problems here (assuming the above code):

var foo = new Foo();
var fooSpawn = foo.spawnClone(); = 'test';

var foo2 = new Foo();
//OOPS: We don't want this! We've messed with the prototype and it stuck!
alert(; //test

The fix to get around that is simple, you just need to do one of two things: Copy off the original prototype and reassign it after the child is created and/or use an extend method (such as JQuery's extend) to augment your child class's prototype prior to created a new instance:

function Foo() {

Foo.prototype.betterSpawnClone = function (){
    //create a copy of the current prototype.
    var protoCopy = Foo.prototype;
    //dynamically assign the prototype.
    Foo.prototype = this;
    //create the clone.
    var clone = new Foo();
    //reset the prototype back to normal.
    Foo.prototype = protoCopy;
    //return our clone.
    return clone;

Anyhow, here's a fiddle to play with. It's a fun little trick with JavaScript and I hope it's useful to someone:

1 comment:

  1. Thanks, exactly what I was looking for !



This form allows some basic HTML. It will only create links if you wrap the URL in an anchor tag (Sorry, it's the Blogger default)