Understanding The Complex And Circular Relationships Between Objects In JavaScript

Posted July 28, 2011 at 11:02 AM by Ben Nadel

Tags: Javascript / DHTML

A couple of months ago, when reading JavaScript: The Good Parts by Douglas Crockford, I have to admit that there was some code discussed in the book that really threw my brain through a loop. Specifically, I had a lot of trouble wrapping my head around the ripple effect that took place when methods were added to the Function() prototype. The relationship between JavaScript objects is complex and, at times, circular. I wanted to take a few minutes to just diagram some of the relationships so that I could refer to it in the future when my brain was having a crisis of mental modeling.

In the following diagram, the black lines indicate "inherits from." The pink lines indicate "composes a prototype." When looking at this, it's important to remember that all object constructors (Object, Function, Date, Number, Boolean, etc.) are functions that are an instance of Function. Oh, and yes, that means Function is an instance of itself.... your mind was just blown!


 
 
 

 
The relationship between objects and constructors in the JavaScript language.  
 
 
 

Clearly, the Function() and Object() prototypes are the hugest players in the JavaScript world. Everything ultimately extends the Object() prototype; but, all constructors extend the Function() prototype. This gives both the Object() and Function() prototypes the ability to change just about every object instance in the JavaScript system.

The most interesting part of this family tree is that both Function() and Object() create a circular relationship with their own prototypes. Meaning, a property added to the Function() prototype immediately becomes available in Function() itself. And, a property added to the Object() prototype immediately becomes available in the Object() itself (by way of the Function() prototype). To see what I mean, take a look at this console output:

>>> Object.someProperty
undefined
>>> Object.prototype.someProperty = "set in Object.prototype";
"set in Object.prototype"
>>> Object.someProperty
"set in Object.prototype"

>>> Function.otherProperty
undefined
>>> Function.prototype.otherProperty = "set in Function.prototype";
"set in Function.prototype"
>>> Function.otherProperty
"set in Function.prototype"

This kind of circular relationship doesn't happen anywhere else in the JavaScript world (as far as I can tell). Never do you create a constructor function and have its prototype properties become available within itself. Pretty funky stuff!

Objects (abstractly) are the core of the JavaScript language. And, as you can see, they create a very interesting family tree. In order to help wrap your head around this, I would recommend taking at look at Cody Lindley's new book, JavaScript Enlightenment. Once you fully understand how objects work, you'll really be able to leverage them in some very powerful ways!




Reader Comments

Jul 28, 2011 at 12:51 PM // reply »
1 Comments

Thanks! This was a good reminder of how much I'm taking for granted everytime I write javascript. Good to slow down and really examine what's happening on the language level.

For instance I often do stuff like this:

var bar = function() {
var obj = {
hello: 'Hello World'
// more methods and properties go here
}
return obj;
}

var foo = function() {
this.print = function() {
console.log(this.hello);
}
}

foo.prototype = bar;

foo.print(); // Hello World

I never really slowed down to think about what's actually happening here. A function that creates an object, then returns that object that I then set to the prototype of another function that I'm effectively treating as an object with its own methods and properties. I just take it for granted at this point, but...damn thats trippy.


Jul 28, 2011 at 1:51 PM // reply »
10,743 Comments

@Will,

Yeah, JavaScript is some funky stuff. And, when it comes to returning objects out of a constructor, it can also get more interesting! If you return an object instance, JavaScript will use that as the result of the constructor invocation. However, if you return a non-object (such as a native string or boolean), JavaScript will ignore the return value and simply return the newly instantiated object.

So, it will honor your return value... but only sometimes, depending on what you return.


Jul 29, 2011 at 1:06 AM // reply »
1 Comments

I am relatively new to javascript so yes, my mind is blown. This has helped my understanding, although the more I learn, the more I realize I don't know !!!


Jul 29, 2011 at 8:53 AM // reply »
10,743 Comments

@John,

Luckily, you don't need to really have this stuff in the forefront of your mind when coding. But, when you get into creating your own "classes" and instances, then this kind of understanding becomes a lot more powerful.


Jul 29, 2011 at 10:35 AM // reply »
1 Comments

Thanks for all of your well thought out and written posts!

I've been trying to wrap my brain around this prototype stuff, but since 95% of my time is in PHP, I'm struggling...but hopefully this will help some.


Oct 29, 2011 at 9:15 PM // reply »
10,743 Comments

@Mazz,

Cool my man, hope it helps!


May 20, 2012 at 4:28 AM // reply »
3 Comments

@Will Vaughn I tried your javascript example but got this error:-

foo.print is not a function


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 21, 2012 at 1:58 AM
Updated: Converting A ColdFusion Query To CSV Using QueryToCSV()
Hi Ben, why do you need to have so many double quotes when adding the field and field name to the row data? ----------------------------------------- <cfset LOCAL.RowData[ LOCAL.ColumnIndex ] = ... read »
AXL
May 21, 2012 at 1:24 AM
URL Rewriting And ColdFusion's WriteToBrowser Image Functionality (CFFileServlet)
@Mounir, Open your lower case URL Rewrite rule and add the following condition. Condition input: {REQUEST_URI} Check if input string: Does Not Match the Pattern Pattern: ^/CFFileServlet/_cf_ca ... read »
May 20, 2012 at 4:28 AM
Understanding The Complex And Circular Relationships Between Objects In JavaScript
@Will Vaughn I tried your javascript example but got this error:- foo.print is not a function ... read »
May 19, 2012 at 5:37 AM
A Graphical Explanation Of Javascript Closures In A jQuery Context
Thanks for this article, but I fear you missed an important point. If variables in the outer context change, these changes affect the inner anonymous functions as well. That means: if you change the ... read »
May 18, 2012 at 3:39 PM
Parsing CSV Data With An Input Stream And A Finite State Machine
Can you use file upload button with this? and read live? or does the file have to already be on the server saved? ... read »
May 18, 2012 at 1:06 AM
VIRGO (Aug. 23-Sept. 22): Dead On The Money!
A friend of mine and I were arguing about astrology and she told me that he believes in astrology. She hasn't provided me with any evidence that the belief makes any sense to me. She she been telling ... read »
May 17, 2012 at 11:32 PM
Using ColdFusion to Handle 404 Errors (Page Not Found) On Development Server
Very easy the configuration. I read a lot pages and I can't find the solution. I open the administrator and change this Administrator/server settings/Error Handlers/Missing Template Handler and p ... read »
May 17, 2012 at 3:13 PM
LOCAL Variables Scope Conflicts With ColdFusion Query of Queries
I never cease to be amazed that almost EVERY random CF issue I come across lands me on your site. Thank you for documenting your findings for the world. ... read »