8

I found some strange behaviour of JavaScript with passing variables as a parameter to function, here is the snippet:

var notWorks = {
    aa: "string",
}

function why() {
    var thisWorks = notWorks;
    $.get("/echo/json").then(function() {
        printVal(notWorks);
        printVal(thisWorks);
    });
    notWorks = {};
}

function printVal(val) {
    console.log(val);
}
why();

The output is:

Object {  }
Object { aa: "string" }

With variable notWorks everything is clear - function in then() is called when the variable is already cleared. But why if I set this object to a new variable it saves initial value of the variable? Object is passing to fuction by link, doesn't it?

Fiddle with example: https://jsfiddle.net/cev8m79y/

Liam
  • 27,717
  • 28
  • 128
  • 190
Shide93
  • 123
  • 6
  • 3
    Your title is like you're scolding JavaScript. :-) – T.J. Crowder Dec 05 '16 at 14:27
  • 3
    The problem is that `$.get` is asynchronous. – Mike Cluck Dec 05 '16 at 14:28
  • you'll need a promise to wait for the async call to come back then run the function – ntgCleaner Dec 05 '16 at 14:29
  • 1
    My mistake, it **isn't** a duplicate of [*How do I return the response from an asynchronous call?*](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call). – T.J. Crowder Dec 05 '16 at 14:29
  • @ntgCleaner that is exactly what the `.then` does. It just needs to be pointed out its asynchronous, as always with these issues :) Note: No parameters were passed in the calling of these functions (apart from the resource path string, but lets ignore that for the sake of a pop-culture reference). – somethinghere Dec 05 '16 at 14:30
  • @somethinghere, Ah thanks, I didn't see the `.then` – ntgCleaner Dec 05 '16 at 14:30
  • 3
    This question has ZERO to do with async. –  Dec 05 '16 at 14:33
  • @George No, it has absolutely NOTHING to do with async. It's about the order in which statements are executed, but the "problem" observed by the OP does not need async calls in any way, shape or form. –  Dec 05 '16 at 14:35
  • if I pass global object to **printVal** it takes actual value of the object on that moment - empty object, it's OK for me. But if I just assign this object to a new variable and then pass it to **printVal** it somehow prints initial value instead of empty object So, what the difference between these two calls? – Shide93 Dec 05 '16 at 14:35
  • Possible duplicate of [Does Javascript pass by reference?](http://stackoverflow.com/questions/13104494/does-javascript-pass-by-reference) – Liam Dec 05 '16 at 14:36

3 Answers3

10

With variable notWorks everything is clear - function in then() is called when the variable is already cleared.

Yes.

But why if I set this object to a new variable it saves initial value of the variable? Object is passing to fuction by link, doesn't it?

This line:

var thisWorks = notWorks;

copies the reference to the object from notWorks to thisWorks. There is no ongoing connection between the variables at that point, they just both refer to the same object.

Then you start the get, and set notWorks to refer to a new, blank object. thisWorks still refers to the previous object. So when the get completes later and you log both of them, you see that thisWorks still points to the original object and notWorks still points to the new, blank object.

Let's throw some ASCII-Art at it (okay, technically it's Unicode-Art):

We start with this:

notWorks: Ref11232−−−+
                     |
                     |
                     |
                     |
                     |  +−−−−−−−−−−−−−−+
                     |  |   (object)   |
                     |  +−−−−−−−−−−−−−−+
                     +−>| aa: "string" |
                        +−−−−−−−−−−−−−−+

(The "Ref11232" is just a placeholder for the value of the object reference. We never actually see the value of an object reference, but you can think of it as a number that tells the JavaScript engine where the object is in memory.)

Then in why, you create a new variable, thisWorks, via var thisWorks:

notWorks: Ref11232−−−+
                     |
                     |
                     |
                     |
                     |  +−−−−−−−−−−−−−−+
                     +−>|   (object)   |
                        +−−−−−−−−−−−−−−+
                        | aa: "string" |
                        +−−−−−−−−−−−−−−+
thisWorks: undefined

And you set it to the same value as notWorks via thisWorks = notWorks:

notWorks: Ref11232−−−+
                     |
                     |
                     |
                     |
                     |  +−−−−−−−−−−−−−−+
                     +−>|   (object)   |
                     |  +−−−−−−−−−−−−−−+
                     |  | aa: "string" |
                     |  +−−−−−−−−−−−−−−+
                     |
thisWorks: Ref11232−−+

Now they both point to the same object.

Then you start get, which has no effect on those variables or objects at all.

Then you give notWorks a new value:

notWorks: Ref84325−−−+
                     |  +−−−−−−−−−−−−−−+
                     +−>|   (object)   |
                        +−−−−−−−−−−−−−−+
                        |              |
                        +−−−−−−−−−−−−−−+

                        +−−−−−−−−−−−−−−+
                     +−>|   (object)   |
                     |  +−−−−−−−−−−−−−−+
                     |  | aa: "string" |
                     |  +−−−−−−−−−−−−−−+
                     |
thisWorks: Ref11232−−+

Then you wait for get to complete, and print them out.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Now I must say this is some tough work being put in an answer here – bugwheels94 Dec 05 '16 at 14:41
  • 1
    @ankitbug94: :-) Explaining object references is like a passion of mine. They're so easy to misunderstand, but once you understand them, you're set for life (er, in programming with objects terms). – T.J. Crowder Dec 05 '16 at 14:42
4

When you do

notWorks = {}

You are creating a new object and assigning it to notWorks but thisWorks is still the reference to the previous object that is why the outputs are different

bugwheels94
  • 30,681
  • 3
  • 39
  • 60
0

It's because you don't really affect the object when the line notWorks = {} is executed, you only remove the reference to it from notWorks. thisWorks still points to the same object in memory.

Shai
  • 3,659
  • 2
  • 13
  • 26