Reputation:
In an app I'm developing, I define a global App
namespace, where I store some properties that I want to access from different functions. For example I might keep a menu menuOpen
property stored in my global App
namespace so the function that I use to handle the Menu interface functionality can share this information easily with a different function that handles something else.
I was having a problem with this a moment ago, after updating this global variable with one function, and then checking a reference to it in the closure of another function, to find the reference didn't reflect my change.
I re-recreated this in a simple example, where I would expect false
to be the result, since bar
changes open
to false
, which should be reflected by state
within foo
's closure before the timeout completes and runs the check against state
:
//set a global variable to be accessed by different parts
//of an application
var open = true;
//create a closure, which waits for a future event,
//then checks the "open" variable when it occurs
function foo() {
//reference to the global variable "open"
var state = open;
//set a timeout, to reflect "a future event", such
//as an event handler
setTimeout(function() {
if (state) {
$('html').text('true');
} else {
$('html').text('false');
}
}, 1000);
}
//change the "open" global within another function
function bar() {
open = false;
}
//create the closure
foo();
//change "open" to false, before the "if(state)" logic
//is called in the closure
bar();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
It was my understanding that a closure keeps a reference to a variable, so state
would reflect any change to open
. How does this actually work? And what would I need to do differently to make foo
's closure aware of open
's change?
Upvotes: 0
Views: 188
Reputation: 707238
As others have said, this issue doesn't have anything to do with closures. It has to do with how Javascript does assignment of different types.
Only objects in Javascript are assigned by pointer. All other data types are assigned by value (e.g. the value is copied). So, when you do:
var state = open;
And, open
is anything other than an object (which includes objects, arrays and functions), then the value in open
is copied to state
and the two variables then have nothing to do with one another.
See this example:
var myNum = 12;
var otherNum = myNum;
document.write("myNum = ", myNum, "<br>"); // 99
document.write("otherNum = ", otherNum, "<br>"); // 12
myNum = 99;
document.write("myNum = ", myNum, "<br>"); // 99
document.write("otherNum = ", otherNum, "<br>"); // still 12
But, if you assigned an object, it would just be a pointer to the original object so if the original was changed, you would see that change in the other reference to that same object:
function log(name, obj) {
document.write(JSON.stringify(obj) + "<br>");
}
var myObj = {greeting: "hello"};
var otherObj = myObj;
log("myObj", myObj);
log("otherObj", otherObj);
myObj.greeting = "bye";
log("myObj", myObj);
log("otherObj", otherObj);
Objects are assigned by pointer to the original. All other types of variables behave as if they are copied and no longer have a connection to the original.
If you want to take a normal non-object variable and get it to behave like you have a pointer to it, then you can put that variable into an object as a property on that object and you can pass the object around. Then, everyone who you pass the object to can examine the property and they will all be looking at exactly the same property value. If one changes it, they will all see the changed value.
Upvotes: 0
Reputation: 85767
This has nothing to do with closures. var x = "a"; var y = x; x = "b"; console.log(y)
outputs "a"
, not "b"
, because y
is a copy of x
.
Closures don't change the normal behavior of variables. A closure is simply a function that uses local variables from a surrounding scope. foo
is a closure because it uses open
; the function passed to setTimeout
is a closure because it uses state
(but state
never changes after being set).
You can fix your code by checking if (open)
directly.
Upvotes: 2