Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Write new article about JavaScript using object graphs.

  • Loading branch information...
commit 6f32301780228d6e9a99f04ae835241cebd38715 1 parent ef92aa1
@creationix authored
View
104 articles/object-graphs.markdown
@@ -0,0 +1,104 @@
+Title: Learning Javascript with Object Graphs
+Author: Tim Caswell
+Date: Thu Sep 30 2010 13:48:55 GMT-0700 (PDT)
+Node: v0.2.2
+
+One of the secrets to being a super effective JavaScript developer is to truly understand the semantics of the language. This article will explain the basic elemental parts of JavaScript using easy to follow diagrams.
+
+## References Everywhere
+
+A variable in JavaScript is simply a label that references a value in memory somewhere. These values can be primitives like strings, numbers, and booleans. They can also be objects or functions.
+
+### Local Variables
+
+In the following example, we will create four local variables in the top-level scope and point them to some primitive values:
+
+<object-graphs/variables.js*>
+
+![variables](object-graphs/variables.dot)
+
+Notice that the two boolean variables point to the same value in memory. This is because primitives are immutable and so the VM can optimize and share a single instance for all references to that particular value.
+
+In the code snippet we checked to see if the two references pointed to the same value using `===` and the result was `true`.
+
+The outer box represents the outermost closure scope. These variables are top-level local variables, not to be confused with properties of the global/window object.
+
+<br style="clear:left"/>
+
+### Objects and Prototype Chains
+
+Objects are just collections of more references to new objects and prototypes. The only special thing they add is the prototype chain for when you try to access a property that's not in the local object, but is in a parent object.
+
+<object-graphs/objects.js*>
+
+![shared-function](object-graphs/objects.dot)
+
+<br style="clear:left"/>
+
+Here we have one object with four properties referenced by the `tim` variable. Also we created a new object that inherits from the first object and referenced it from `jack`. Then we overrode two properties in the local object.
+
+Now when looking up `jack.likesJavaScript`, we first find the object that `jack` references. Then we look for the `likesJavaScript` property. Since it's not there, we look at the parent object and find it there. Then we find the `true` value it references.
+
+### The Global Object
+
+Ever wondered why tools like [jslint][] always tell you to not forget to put `var` statements before your variables. Well, here is what happens if you forget.
+
+<object-graphs/globals.js>
+
+![variables](object-graphs/globals.dot)
+
+Notice that `likesJavaScript` is now a property of the global object instead of a free variable in the outer closure. This only really matters if you're going to be mixing several scripts. But in any real program that's exactly what you're going to be doing.
+
+Always remember to put those `var` statements in there to keep your variable's scope to the current closure and it's children. You'll be much happier by following this simple rule.
+
+If you must put something on the global object, do it explicitly with `window.woo` in the browser or `global.goo` in node.js.
+
+<br style="clear:left"/>
+
+## Functions and Closures
+
+JavaScript isn't just a series of chained data structures. It contains executable, callable code known as functions. These functions create nested scopes and closures.
+
+### Visualizing Closures
+
+Functions can de drawn as nested scopes and as special objects that contain executable code as well as properties.
+
+In this example we will create a simple factory method that generates a closure and returns a function.
+
+<object-graphs/closure.js*>
+
+![variables](object-graphs/closure.dot)
+
+<br style="clear:left"/>
+
+When we call `description1()`, the VM looks up the function that it references and executes it. Since that function looks for a local variable named `name`, it finds it in the parent closure scope. This factory method is nice since each generated function has it's own space for local variables.
+
+See the article [why use closure][] for more in-depth reading on this topic and it's many uses.
+
+### Shared Functions and `this`
+
+Sometimes for performance reasons, or because you just plain prefer the style, JavaScript provides a `this` keyword that allows you to reuse a function object in different scopes depending on how it was called.
+
+Here we'll create a few objects that all share a common function. This function will reference `this` internally to show how it changes from call to call.
+
+<object-graphs/functions.js*>
+
+![variables](object-graphs/functions.dot)
+
+<br style="clear:left"/>
+
+*(Note I drew the objects and literals inside the closure to make the diagram clearer. There is no special meaning to this. Only free variables and function bodies are affected by closure nesting)*
+
+In the diagram, we see that even though `Fred.description` was set to `Lane.description`, it's really only referencing the function. Thus all three references have equal ownership of the anonymous function. This is why I try to not call functions on constructor prototypes "methods", because that implies some sort of binding of the function to the constructor and it's "class". *(see [what is this][] for more details on the dynamic nature of `this`)*
+
+## Conclusion
+
+I've had tons of fun using diagrams to visualize these data structures. My hope is that this helps those of us that are visual learners to get a better grasp of JavaScript semantics. I have past experience as both a front-end designer/developer and as a server-side architect. I hope my unique perspective is useful to those coming from the world of design and learning the innards of this wonderful language known as JavaScript.
+
+*(NOTE, all the diagrams are [graphviz][] dot files and can be seen [here][])*
+
+[jslint]: http://jslint.com/
+[what is this]: http://howtonode.org/what-is-this
+[why use closure]: http://howtonode.org/why-use-closure
+[graphviz]: http://www.graphviz.org/
+[here]: http://github.com/creationix/howtonode.org/tree/master/articles/object-graphs/
View
47 articles/object-graphs/closure.dot
@@ -0,0 +1,47 @@
+digraph finite_state_machine {
+ size="8,5"
+ rankdir = "LR"
+
+ subgraph cluster_0 {
+ style =rounded;
+
+ /* Free Variables */
+ node [shape = plaintext, style=""]
+ description1;description2;
+ subgraph cluster_1 {
+
+ /* Free Variables */
+ node [shape = plaintext, style=""]
+ name1 [label="name"];
+
+ subgraph cluster_2 {
+ node [shape=Mrecord, fillcolor=orange, style=filled];
+ fn1 [label="<__proto__>function () \{ return name; \}"];
+ }
+ }
+ subgraph cluster_3 {
+
+ /* Free Variables */
+ node [shape = plaintext, style=""]
+ name2 [label="name"];
+
+ subgraph cluster_4 {
+ node [shape=Mrecord, fillcolor=orange, style=filled];
+ fn2 [label="<__proto__>function () \{ return name; \}"];
+ }
+ }
+
+
+ }
+
+ /* Literals */
+ node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ cloe [label="\"Cloe the Closure\""]
+ albert [label="\"Albert the Awesome\""]
+
+
+ description1 -> fn1:__proto__;
+ description2 -> fn2:__proto__;
+ name1 -> cloe;
+ name2 -> albert;
+}
View
9 articles/object-graphs/closure.js
@@ -0,0 +1,9 @@
+function makeClosure(name) {
+ return function () {
+ return name;
+ };
+}
+var description1 = makeClosure("Cloe the Closure");
+var description2 = makeClosure("Albert the Awesome");
+console.log(description1());
+console.log(description2());
View
43 articles/object-graphs/functions.dot
@@ -0,0 +1,43 @@
+digraph finite_state_machine {
+ size="8,5"
+ rankdir = "LR"
+
+ subgraph cluster_0 {
+ style =rounded;
+
+ /* Free Variables */
+ node [shape = plaintext, style=""]
+ Lane; Fred; description;
+ subgraph cluster_1 {
+ node [shape=Mrecord, fillcolor=orange, style=filled];
+ fn1 [label="<__proto__>function () \{ return this.name; \}"];
+ }
+
+ /* Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ obj1 [label = "<__proto__>Object|<name>name|<description>description"];
+ obj2 [label = "<__proto__>Object|<description>description|<name>name"];
+ /* Literals */
+ node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ name [label="\"Lane the Lambda\""]
+ name2 [label="\"Fred the Functor\""]
+
+
+ }
+ /* Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ obj3 [label = "<__proto__>Object|<name>name"];
+ /* Literals */
+ node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ name3 [label="\"Zed the Zetabyte\""]
+
+
+ Lane -> obj1:__proto__;
+ obj1:name -> name;
+ obj1:description -> fn1:__proto__;
+ Fred -> obj2:__proto__;
+ obj2:name -> name2;
+ obj2:description -> fn1:__proto__;
+ obj3:name -> name3;
+ description -> fn1:__proto__;
+}
View
18 articles/object-graphs/functions.js
@@ -0,0 +1,18 @@
+var Lane = {
+ name: "Lane the Lambda",
+ description: function () {
+ return this.name;
+ }
+};
+var description = Lane.description;
+var Fred = {
+ description: Lane.description,
+ name: "Fred the Functor"
+};
+// Call the function from four different scopes
+console.log(Lane.description());
+console.log(Fred.description());
+console.log(description());
+console.log(description.call({
+ name: "Zed the Zetabyte"
+}));
View
29 articles/object-graphs/globals.dot
@@ -0,0 +1,29 @@
+digraph finite_state_machine {
+ size="8,5"
+ rankdir = "LR"
+
+ subgraph cluster_0 {
+ style =rounded;
+
+ /* Free Variables */
+ node [shape = plaintext, style=""]
+ name; age; isProgrammer;
+
+ }
+
+ /* Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ global [label = "<__proto__>Global|<likesJavaScript>likesJavaScript"];
+
+ /* Literals */
+ node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ timcaswell [label="\"Tim Caswell\""]
+ n28 [label="28"]
+ true [label="true"]
+
+ name -> timcaswell;
+ age -> n28;
+ isProgrammer -> true;
+ global:likesJavaScript -> true;
+
+}
View
5 articles/object-graphs/globals.js
@@ -0,0 +1,5 @@
+var name = "Tim Caswell";
+var age = 28;
+var isProgrammer = true;
+// Oops we forgot a var
+likesJavaScript = true;
View
37 articles/object-graphs/objects.dot
@@ -0,0 +1,37 @@
+digraph finite_state_machine {
+ size="8,5"
+ rankdir = "LR"
+
+ subgraph cluster_0 {
+ style =rounded;
+ /* Free Variables */
+ node [shape = plaintext, style=""]
+ tim; jack;
+
+ }
+
+ /* Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ obj1 [label = "<__proto__>Object|<name>name|<age>age|<isProgrammer>isProgrammer|<likesJavaScript>likesJavaScript"];
+ obj2 [label = "<__proto__>Object|<name>name|<age>age"];
+
+
+ /* Literals */
+ node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ s_tim [label="\"Tim Caswell\""]
+ s_jack [label="\"Jack Caswell\""]
+ true [label="true"]
+ n4 [label="4"]
+ n28 [label="28"]
+
+ /* Links */
+ obj2:__proto__ -> obj1:__proto__ [color=blue];
+ tim -> obj1:__proto__;
+ obj1:name -> s_tim;
+ obj1:age -> n28;
+ obj1:isProgrammer -> true;
+ obj1:likesJavaScript -> true;
+ jack -> obj2:__proto__;
+ obj2:name -> s_jack;
+ obj2:age -> n4;
+}
View
14 articles/object-graphs/objects.js
@@ -0,0 +1,14 @@
+// Create a parent object
+var tim = {
+ name: "Tim Caswell",
+ age: 28,
+ isProgrammer: true,
+ likesJavaScript: true
+}
+// Create a child object
+var jack = Object.create(tim);
+// Override some properties locally
+jack.name = "Jack Caswell";
+jack.age = 4;
+// Look up stuff through the prototype chain
+jack.likesJavaScript;
View
25 articles/object-graphs/variables.dot
@@ -0,0 +1,25 @@
+digraph finite_state_machine {
+ size="8,5"
+ rankdir = "LR"
+
+ subgraph cluster_0 {
+ style =rounded;
+
+ /* Free Variables */
+ node [shape = plaintext, style=""]
+ name; age; isProgrammer; likesJavaScript;
+
+ }
+
+ /* Literals */
+ node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ timcaswell [label="\"Tim Caswell\""]
+ n28 [label="28"]
+ true [label="true"]
+
+ name -> timcaswell;
+ age -> n28;
+ isProgrammer -> true;
+ likesJavaScript -> true;
+
+}
View
14 articles/object-graphs/variables.js
@@ -0,0 +1,14 @@
+// Create a parent object
+var tim = {
+ name: "Tim Caswell",
+ age: 28,
+ isProgrammer: true,
+ likesJavaScript: true
+}
+// Create a child object
+var jack = Object.create(tim);
+// Override some properties locally
+jack.name = "Jack Caswell";
+jack.age = 4;
+// Look up stuff through the prototype chain
+jack.likesJavaScript;
Please sign in to comment.
Something went wrong with that request. Please try again.