3

Here's a simple example:

  1| window.gamelogic = {};
  2| var g = gamelogic;
  3| g.points = 1;
  4| g.array = ["foo","bar"];
  5| var b = g.points;
  6| b = b + 1;
  7| console.log(window.gamelogic);
  8| console.log(b);

This will print:

Object { points=1, array=[2] }
2

So there's 2 things to note here:

  1. A (seemingly local) variable - g - when set to a global object and updated, also updates the golbal object - window.gamelogic. (Updating g also updated window.gamelogic).

  2. A local int, b (set to a global int, points), does not update the global variable when it is changed. (updating b did not update window.gamelogic.points)

Based on the first point, one would think that when a var is pointed to a global object, you're actually just creating another pointer to the same memory location of that global object. This would explain why updating g also updates window.gamelogic.

However, b not updating window.gamelogic.points seems to counter this argument.

What is going on here?

Travis Heeter
  • 13,002
  • 13
  • 87
  • 129
  • 6
    It has nothing to do with it being global. Objects in JS are reference types. Any mutation of an object will be seen from all references. Primitives are immutable, so they do not share this characteristic. –  Dec 30 '15 at 17:47
  • 4
    Remember, JS is a "by value" language, so this helps to understand the primitives; it's assigning a copy. Object assignment is also "by value" but because the type itself is a reference type, you never actually have direct access to the object, so the copy made is of the reference, not the object itself. –  Dec 30 '15 at 17:49
  • The other important part is that objects are mutable. – Felix Kling Dec 30 '15 at 17:50
  • 1
    Read also the second answer and onwards in https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language… I want to find a better duplicate, though, since the top answer there is absolutely terrible. – Ry- Dec 30 '15 at 18:02
  • 1
    @squint, I think I need that second comment embroidered on a cushion. Thanks for making that clear :) – Andy Dec 30 '15 at 18:04

4 Answers4

6

In JavaScript, variables (and properties) contain values. Values can have many different types (number, string, boolean), one of which is object reference, which is a reference to an object but isn't the actual object itself. An easy way to think of an object reference is that it's just a number, like an index into a really big array, telling us where the object is. (That's not literally true, but it's a useful way to think of it.) Or in non-programming terms, Joe may have a piece of paper with "123 Any St." written on it, which is where Joe's house is. The paper is a variable (or property); the "123 Any St." is a value (an object reference, in this case), and the house is an object.

Objects are not values, and so they cannot be stored in variables or properties (or passed as function arguments). Only references to them can be.

When you assign a value to a variable or property (or pass it into a function as an argument), you're copying the value into it from the source. So a = b copies the value from b into a. When b contains an object reference, it's the reference, not the object, that gets copied; then a and b both refer to the same object. It's like Mary getting out a piece of paper (a) and copying down what's on Joe's piece of paper (b). Now both pieces of paper say where Joe's house is. The house isn't copied, just the information telling us where it is.

With that in mind, let's look at your code. When you do

window.gamelogic = {};

it creates an object and the copies its reference (a value) into the property gamelogic. Here's a rough sketch of what's in memory at that point, omitting a lot of unnecessary details:

                 +-------------------+
                 | (stuff omitted)   |       +-----------+
window:ref429--->| gamelogic: ref758 |------>|           |
                 +-------------------+       +-----------+

Then you do this:

var g = gamelogic;

which (waves hands) creates a variable (I'll explain the hand waving later) and assigns (copies) the value in gamelogic to it. Since that value is an object reference, g and gamelogic now point the same place; that is, they refer to the same object:

                 +-------------------+
                 | (stuff omitted)   |    
window:ref429--->| gamelogic: ref758 |---+
                 +-------------------+   |   +-----------+
                                         +-->|           |
                                         |   +-----------+
g: ref758--------------------------------+

Then you do

g.points = 1;

which creates a property on that object called points and copies the value 1 into it:

                 +-------------------+
                 | (stuff omitted)   |    
window:ref429--->| gamelogic: ref758 |---+
                 +-------------------+   |   +-----------+
                                         +-->| points: 1 |
                                         |   +-----------+
g: ref758--------------------------------+

Let's highlight what we've done here: We haven't changed the value in g in any way, it's still the same as it was: A reference to the object that gamelogic also references. What we've done is changed the state of that object (by adding a property to it). This is one of the key things about objects: They have state that can be changed. When that state is changed, it doesn't matter which copy of the reference to it you have when you look at it; you'll see the same object, with its (updated) state, regardless.

Okay, continuing:

g.array = ["foo","bar"];

which creates an array (which is an object), and creates a property called array on our object, and copies the value of the array's reference into the property:

                 +-------------------+
                 | (stuff omitted)   |    
window:ref429--->| gamelogic: ref758 |---+
                 +-------------------+   |   +---------------+     +----------+
                                         +-->| points: 1     |     | 0: "foo" |
                                         |   | array: ref804 |---->| 1: "bar" |
g: ref758--------------------------------+   +---------------+     +----------+

Then you do:

var b = g.points;

which (waves hands) creates a variable and copies the value from g.points (1) into it:

                 +-------------------+
                 | (stuff omitted)   |    
window:ref429--->| gamelogic: ref758 |---+
                 +-------------------+   |   +---------------+     +----------+
                                         +-->| points: 1     |     | 0: "foo" |
                                         |   | array: ref804 |---->| 1: "bar" |
g: ref758--------------------------------+   +---------------+     +----------+
b: 1

Then

b = b + 1;

gets the value 1 from b, adds 1 to it, and stores the new value (2) in b. g.points is completely unaffected:

                 +-------------------+
                 | (stuff omitted)   |    
window:ref429--->| gamelogic: ref758 |---+
                 +-------------------+   |   +---------------+     +----------+
                                         +-->| points: 1     |     | 0: "foo" |
                                         |   | array: ref804 |---->| 1: "bar" |
g: ref758--------------------------------+   +---------------+     +----------+
b: 2

The key points above are:

  • Variables and properties (and function arguments) contain values.
  • A values has a type, such as string, number, boolean, or object reference.
  • An object reference is just a value that says where an object is.
  • Objects are not values; references to objects are values.
  • Objects have state that can be changed.*

(* If they allow it. It's possible to create an object that doesn't allow its state to be changed; those are called "immutable" objects. And it can be very, very handy and powerful to do that. In JavaScript, you do that with Object.freeze and similar, since by default objects are very loose and you can add properties to them just by assigning. In many other languages, it's more basic: You just don't define any public field that can be changed, and don't define any public methods that change the object's state.)


About that "creates a variable" hand-waving, I was ignoring two details there because they weren't important then:

  1. In JavaScript, var declarations are processed before the code starts running, so the variables g and b were both already created before the first line of your step-by-step code ran. Initially, the had the value undefined in them.

  2. Because you used var at global scope, b and g became properties of the global object, which is what window points to. In fact, window itself is a property of the global object. Up through ES5, all globals were properties of the global object. (In ES6/ES2015, we have a new category of globals that aren't: Ones created with let, const, or class.)

So technically, our first diagram should have looked like this:

+--------------------------+
|   +-------------------+  |
|   | (stuff omitted)   |  |
+-->| window: ref429    |--+    +-----------+
    | gamelogic: ref758 |------>|           |
    | g: undefined      |       +-----------+ 
    | b: undefined      |
    +-------------------+

...but, well, that seems like it would have been less than useful. :-)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    **Wow**. I love how, sometimes, you will take a look at a well written answer and think 'Meh, this is rudimentary stuff, but let me skim through'....and then...you get draaawwwwn in and learn, um, **quite** a bit. Thank you for this awesome, well written answer :-) – AmmarCSE Dec 31 '15 at 11:17
2

This isn’t a difference between integers and objects*; you’re performing different operations on each. Consider this, no integers involved, but instead the same operation: assigning to a variable, rather than to a property on the object that is the value of that variable:

var a = {};
var b = a;
var c = a;

b.x = 'hello, world!'; // a, b, and c now all refer to { x: 'hello, world!' }

c = { y: 'foo' };      // a and b still refer to { x: 'hello, world!' };
                       // c refers to a different object now

Think of this as everything being a reference, and = overwriting references. You can change what a variable or property references, but changing the property of an object (which a variable or property can reference) changes… the object.

Note that this is the same way as many other common languages work, including C#, Java, and Python.


* Someone might argue primitives are pass-by-value or copied, but as they’re immutable, you can’t tell the difference.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • There are **no** real references in JavaScript. – SergeyA Dec 30 '15 at 17:54
  • 1
    @SergeyA: can you explain the difference between a real and an unreal reference? – Felix Kling Dec 30 '15 at 17:57
  • 2
    @SergeyA: That depends on what you mean by a “real reference”. I think it’s about as arguable that there are no “real pointers” in JavaScript. – Ry- Dec 30 '15 at 17:57
  • @FelixKling, languages with 'real references' allow one to write a `swap` function with 3 assignment operators. This is a well-known litmus test. – SergeyA Dec 30 '15 at 17:58
  • 1
    @SergeyA: I'm pretty sure Ryan is talking about "value references", not "variable references" (what you seem to refer to). There isn't only one kind of "reference" in programming. – Felix Kling Dec 30 '15 at 18:00
  • @FelixKling, what is a 'value reference'? Types are either 'values' or 'references', 'value reference' is an oxymoron. – SergeyA Dec 30 '15 at 18:02
  • @SergeyA: basically an object reference in the context of JavaScript. If we can agree on that a reference is a memory address, then an object reference is the memory address of an object, and a variable reference is the memory address of another variable. Object references clearly exist in JS. – Felix Kling Dec 30 '15 at 18:04
  • 1
    @SergeyA: I’m talking about references in the sense that C# has reference types. I’m not referencing (for example) its `ref` nor C++-style references. – Ry- Dec 30 '15 at 18:04
  • "Reference type" is the term I missed. This is actually used in the spec as well. – Felix Kling Dec 30 '15 at 18:07
  • 1
    @FelixKling , all this Java/JavaScript (not familiar with C#, suppose same there) 'reference' is marketing mumbo-jumbo. Someone pushed the idea that pointers are not safe, than provided a language which does not have pointer -so the language is safe now. What was done in reality, is a language which does not have **references**, has only pointers, but lacks pointer arithmetics or address of operator. I refuse to buy it. – SergeyA Dec 30 '15 at 18:07
  • 1
    @SergeyA: Pointers / references.... all the same to me. It's more important *what* those pointers / references are pointing to. – Felix Kling Dec 30 '15 at 18:10
  • 1
    @FelixKling, this is the attitude I am fighting with. There is a fundamental difference between reference and pointers, and I did outline it above. – SergeyA Dec 30 '15 at 18:12
  • 1
    @SergeyA: Trying to apply C++ semantics to everything is just not something that works. *Reference type* is a perfectly well-known term. – Ry- Dec 30 '15 at 18:13
  • I am not applying semantics, I am just showing that the semantic is in fact the same - the only difference is a syntax. – SergeyA Dec 30 '15 at 18:14
  • @SergeyA: The semantics are also the same as references except for assignment. So can I say the assignment operator works differently, just as drawing a comparison to pointers means the `.` operator has to work differently? The similar-looking syntax misleads into thinking that’s what has to be compared. Also, the very concepts of references and pointers are essentially the same. C++’s implementation of them doesn’t change that. – Ry- Dec 30 '15 at 18:18
  • @RyanO'Hara, no, they are very different. (by the way, reference type is well known. It is 'value reference' I was puzzled with). References do not create new objects, and instead serve as aliases for already existing objects. pointers are independent objects. Using `operator =` model alone does not suffice. I will explain in my answer why. – SergeyA Dec 30 '15 at 18:24
1

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.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • I wouldn't say JS has "pointers". Nothing in the language can be used identically to how actual pointers are used in other languages. –  Dec 30 '15 at 17:51
  • @squint, it does not have pointer arithmetics nor it has address-taking operator. Other than that, pointers mental model is really helpful in understanding those questions - which are true conundrum otherwise. – SergeyA Dec 30 '15 at 17:53
  • 2
    It might help to edit your answer to reflect that - something like "While JS doesn't have pointers, a traditional pointer model _can_ be a useful way to to approach the language". Or something to give it more clarity. – Andy Dec 30 '15 at 17:57
  • 1
    @Andy, this is a wonderful choice of words. I gladly accept it. – SergeyA Dec 30 '15 at 18:00
  • IMO, "pointer" alone is just too misleading. The fact that you can't truly dereference it in any way takes away all that a pointer really is. Maybe a "boxed pointer" is better, or something to show that it's more of a magic pointer that never lets you touch (copy/replace) the memory directly but does let you mutate the internal structure of the object. –  Dec 30 '15 at 18:03
  • @squint, this is exactly what you do when you access an object in JS: you **derefence** the pointer. – SergeyA Dec 30 '15 at 18:05
  • @SergeyA: No, if you could actually dereference the pointer, you'd be able to copy or replace the whole object in memory. You can't do that in JS. What you're doing in JS is mutating the internal structure, with the underlying implementation doing some dereferencing for you. It just can't be used like an actual pointer. –  Dec 30 '15 at 18:09
  • @squint, why? When you do `obj.value = 42` you are *dereferencing* obj and accessing *value* of the pointed-to object. It is exact replica of C/C++ `Obj* obj; obj->value = 42` – SergeyA Dec 30 '15 at 18:10
  • The internals are doing some dereferencing but you can never directly dereference it. If you could, you'd be able to replace the entire `obj` in your example. `*obj = {another: "object"}`. Certainly pointers are at work at some level, but not as a language feature. –  Dec 30 '15 at 18:14
  • @squint, well, there is no object dereferencing operator, only member-access dereferencing operator. Still the same pointer, only with less available operators. – SergeyA Dec 30 '15 at 18:16
  • Well if there's no dereferencing operator, you can't dereference it. That doesn't mean it isn't dereferenced at some level. Seems pointless (no pun intended) to have a feature that you really can't use like the feature name implies. –  Dec 30 '15 at 18:23
  • 1
    *"let's take into account the fact that objects in JS can be undefined"* That's wrong. `undefined` is a primitive value, just like `true`. It's not an object or pointer. – Felix Kling Dec 31 '15 at 14:40
0

g is referencing the same object referred by gamelogic, so any changes to object referred by g reflect in gamelogic.

here,

 var b = g.points;
 b = b + 1;

you have set b to literal value 1 and then added 1 to it, so it's now 2 and it doesn't affect g.points .

Ramanlfc
  • 8,283
  • 1
  • 18
  • 24