The simple mental model to use with JavaScript is to forget what has been told in numerous books and accept the fact that JavaScript has pointers. While according to language specification JavaScript has no pointers, a traditional pointer model can be a useful way to to approach the language.
When thought like this, it has only pointers for objects and value types for primitives. When this model is used, there is no mystery whatsoever. Here is breakdown:
window.gamelogic = {}; // creates an object, stores *pointer* to the object in window.gamelogic (global)
var g = gamelogic; // creates an pointer g, which points to the same object as gamelogic
g.points = 1; // Access object by pointer, set's object value to 1
g.array = ["foo","bar"]; // same
var b = g.points; // g.points is a primitive, so b is a copy of g.points
b = b + 1; // b is incremented indepently of g.points
And the statement that JavaScript has references is simply confusing. It does not have references at all.
I will explain why I maintain that JavaScript has no references. First of all, let's define some basics. It is usually accepted that references are another name of the object, while pointers are independent objects which can be used to access the object they point to. For that matter, pointers do not have to have actual memory addresses in them. It is enough to that having a pointer allows one to access the object pointed by it, and that pointer itself is an object, which can be modified.
On the other hand, references are not indepented objects. Instead, they are aliases, or second names, for already existing object. A pointer can be changed and point to a different object. A reference can not - it will always be the second name for the object it was assigned to. The difference is subtle, but crucial.
Both pointers and references are what I can call 'an indirect access' type - that is, the type which allows indirect access to underlying object.
So, let's consider following example:
function foo(datum) {
datum = datum2;
}
var dat = datum1;
// Initialize dat
foo(dat);
// what is dat now? (1)
What will happen within foo()? We all know that dat
in the point (1) will still hold the value of datum1, despite seemingly being changed in foo(). We might assume the whole object (dat) is passed by value to foo()
- that is, copied into independent object and give to foo()
- and such operation preserved original dat
from any modification.
However, as we all well know, if we are to modify foo as following:
function foo(datum) {
datum.property = 42;
}
We will know that at point (1) dat.property is also 42. (Assume it was not set to this value before). That means, that the suggestion about whole dat object being passed to foo is wrong - modification of the copy would not affect the original. What we would also notice is that the original datum1 object also has the property set to 42 - which means that passing into functions are not really different from simple assignments. For the sake of simplicity, we can even remove the function call from the picture, and use following code:
var datum1 = Object();
var datum2 = Object();
// datum1 and datum2 are differently initialized
var dat = datum1;
dat = datum2; // datum1 and datum2 are unchanged
dat.property = 42; // now datum2 property is 42, datum1 is unchanged
dat = datum1; // datum2 is unchanged, still has 42
dat.property = 42; // datum1.property is 42
So, what is dat
? It is not the object itself, since modifing it changes other objects (would not be the case if it was). It is some way of an indirect access type I mentioned earlier, so it is either pointer or reference. Let's see how it plays. Let's assume it is a reference.
If it would be a reference, though,
dat = datum1; // (1)
dat = datum2; // (2)
would change datum1 (and make it equal to datum2). Since references are aliases, line (1) would establish dat to be an alias to datum1, and line (2) would change an aliased (datum1) to be the same as datum2. Not the case here.
Let's check if pointer logic applies. Let's assume, dat is a pointer. First to lines (dat = datum1; dat = datum2
) do fit well - dat is a pointer, and it stopped pointing to datum1 and now points to datum2. So far so good. What about next?
Let's look at dat.property = 42;
. If we are to assume dat is a pointer, the only sane way to look at dat.
is to assume (.) to be a member dereferencing operator. That is, an operator which dereferences a pointer on the left an access the member of dereferenced object on the right. Read like this, we can clearly see that pointer analogy holds - dereferenced dat
points to datum1, and property
of datum1 is changed to 42. Same logic applied further on still holds.
So pointer analogy works better than reference! To convince further, let's take into account the fact that objects in JS can be undefined. This makes no sense with references - as they are second names, what might a second name of the no-object mean (no-entity can not have a second or first name), while pointers make everything clear - of course, a pointer, as independent object, can point to nothing.
Granted, those are not the same pointers as in C/C++ - they do not hold a direct memory address, and there is no pointer arythmetics on them. Still, pointer analogy holds much better and clears confusion much easier than a reference one.