In the following example, we will create four local variables in the top-level scope and point them to some primitive values:
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
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.
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.
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 references. Then we look for 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.
Always remember to put those
var statements in there to keep your variable's scope to the current closure and its 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.
Functions and Closures
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.
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 its own space for local variables.
See the article why use closure for more in-depth reading on this topic and its many uses.
Shared Functions and
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.
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 its "class". (see what is this for more details on the dynamic nature of