Permalink
Browse files

Update the object-graph article to see closures better.

Scope chains are much easier to visualize properly than nested boxes.
  • Loading branch information...
1 parent c47d514 commit 5c1993b543b5c376e6ada6f5ca5dd2bd5fdb183e @creationix creationix committed Oct 9, 2010
@@ -57,11 +57,11 @@ If you must put something on the global object, do it explicitly with `window.wo
## 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.
+JavaScript isn't just a series of chained data structures. It contains executable, callable code known as functions. These functions create chained scopes and closures.
### Visualizing Closures
-Functions can be drawn as nested scopes and as special objects that contain executable code as well as properties.
+Functions can be drawn as special objects that contain executable code as well as properties. Every function has a special `[scope]` property that represents the environment it was in when it was defined. If a function is returned from another function then this reference to the old environment is closed over by the new function in a "closure".
In this example we will create a simple factory method that generates a closure and returns a function.
@@ -71,7 +71,7 @@ In this example we will create a simple factory method that generates a closure
<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.
+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 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.
@@ -2,46 +2,38 @@ 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; \}"];
- }
- }
-
-
- }
+ /* Execution Contexts */
+ node [shape=Mrecord, fillcolor=beige, style=filled];
+ top [label="<__proto__>[Scope]|<description1>description1|<description2>description2"];
+ closure1 [label="<__proto__>[Scope]|<name>name"];
+ closure2 [label="<__proto__>[Scope]|<name>name"];
+
+ /* Normal Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+
+ /* Function Objects */
+ node [shape = Mrecord, fillcolor=orange, style=filled];
+ fn1 [label="<__proto__>[Function]|<__scope__>[scope]"];
+ fn2 [label="<__proto__>[Function]|<__scope__>[scope]"];
/* Literals */
- node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ node [shape = plaintext, fillcolor=gray92, style="filled,rounded"];
cloe [label="\"Cloe the Closure\""]
albert [label="\"Albert the Awesome\""]
+ /* References */
+ top:description1 -> fn1:__proto__;
+ top:description2 -> fn2:__proto__;
+ closure1:name -> cloe;
+ closure2:name -> albert;
+ fn1:__scope__ -> closure1:__proto__;
+ fn2:__scope__ -> closure2:__proto__;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ closure1:__proto__ -> top:__proto__;
+ closure2:__proto__ -> top:__proto__;
+
+
- description1 -> fn1:__proto__;
- description2 -> fn2:__proto__;
- name1 -> cloe;
- name2 -> albert;
}
@@ -2,42 +2,37 @@ 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; \}"];
- }
+ /* Execution Contexts */
+ node [shape=Mrecord, fillcolor=beige, style=filled];
+ top [label="<__proto__>[Scope]|<Lane>Lane|<description>description|<Fred>Fred"];
- /* 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\""]
+ /* Normal Objects */
+ node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
+ ob_Lane [label = "<__proto__>[Object]|<name>name|<description>description"];
+ ob_Fred [label = "<__proto__>[Object]|<description>description|<name>name"];
+ ob_1 [label = "<__proto__>[Object]|<name>name"];
+ /* Function Objects */
+ node [shape = Mrecord, fillcolor=orange, style=filled];
+ fn1 [label="<__proto__>function () \{ return this.name; \}"];
- }
- /* Objects */
- node [shape = Mrecord, fillcolor=lightskyblue, style=filled];
- obj3 [label = "<__proto__>Object|<name>name"];
/* Literals */
- node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ node [shape = plaintext, fillcolor=gray92, style="filled,rounded"];
+ name [label="\"Lane the Lambda\""]
+ name2 [label="\"Fred the Functor\""]
name3 [label="\"Zed the Zetabyte\""]
+ /* References */
+ top:Lane -> ob_Lane:__proto__;
+ top:Fred -> ob_Fred:__proto__;
+ ob_Lane:name -> name;
+ ob_Lane:description -> fn1:__proto__;
+ ob_Fred:name -> name2;
+ ob_Fred:description -> fn1:__proto__;
+ ob_1:name -> name3;
+ top:description -> fn1:__proto__;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
- 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__;
}
@@ -1,29 +1,26 @@
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"];
+ size="8,5"
+ rankdir = "LR"
+
+ /* Execution Contexts */
+ node [shape=Mrecord, fillcolor=beige, style=filled];
+ top [label="<__proto__>[Scope]|<name>name|<age>age|<isProgrammer>isProgrammer"];
+ global [label="<__proto__>[Scope global]|<likesJavaScript>likesJavaScript"];
/* Literals */
- node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ node [shape = plaintext, fillcolor=gray92, style="filled,rounded"];
timcaswell [label="\"Tim Caswell\""]
n28 [label="28"]
true [label="true"]
- name -> timcaswell;
- age -> n28;
- isProgrammer -> true;
+ /* References */
+ top:name -> timcaswell;
+ top:age -> n28;
+ top:isProgrammer -> true;
global:likesJavaScript -> true;
+ /* Inheritance Chains */
+ edge [style=dashed]
+ top:__proto__ -> global:__proto__;
+
}
@@ -2,36 +2,36 @@ digraph finite_state_machine {
size="8,5"
rankdir = "LR"
- subgraph cluster_0 {
- style =rounded;
- /* Free Variables */
- node [shape = plaintext, style=""]
- tim; jack;
+ /* Execution Contexts */
+ node [shape=Mrecord, fillcolor=beige, style=filled];
+ top [label="<__proto__>[Scope]|<tim>tim|<jack>jack"];
- }
-
- /* Objects */
+ /* Normal 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"];
+ node [shape = plaintext, fillcolor=gray92, 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__;
+ /* References */
+ top:tim -> obj1:__proto__;
obj1:name -> s_tim;
obj1:age -> n28;
obj1:isProgrammer -> true;
obj1:likesJavaScript -> true;
- jack -> obj2:__proto__;
+ top:jack -> obj2:__proto__;
obj2:name -> s_jack;
obj2:age -> n4;
+
+ /* Inheritance Chains */
+ edge [style=dashed]
+ obj2:__proto__ -> obj1:__proto__;
+
}
@@ -1,25 +1,21 @@
digraph finite_state_machine {
size="8,5"
rankdir = "LR"
-
- subgraph cluster_0 {
- style =rounded;
- /* Free Variables */
- node [shape = plaintext, style=""]
- name; age; isProgrammer; likesJavaScript;
-
- }
+ /* Execution Contexts */
+ node [shape=Mrecord, fillcolor=beige, style=filled];
+ top [label="<__proto__>[Scope]|<name>name|<age>age|<isProgrammer>isProgrammer|<likesJavaScript>likesJavaScript"]
/* Literals */
- node [shape = plaintext, fillcolor=lightGrey, style="filled,rounded"];
+ node [shape = plaintext, fillcolor=gray92, style="filled,rounded"];
timcaswell [label="\"Tim Caswell\""]
n28 [label="28"]
true [label="true"]
- name -> timcaswell;
- age -> n28;
- isProgrammer -> true;
- likesJavaScript -> true;
-
+ /* References */
+ top:name -> timcaswell;
+ top:age -> n28;
+ top:isProgrammer -> true;
+ top:likesJavaScript -> true;
+
}

0 comments on commit 5c1993b

Please sign in to comment.