I've recently read about closures in javascript and if I understand it correctly, it's when an inner function has access to variables in an an outer function. If so, under what use cases should I be using closures?
When you're thinking about writing a function, but realize that that function needs to do some internal state-keeping to determine its actions. The state should be stored, read and modified in a variable — but you don't want that variable existing outside of the function (if other functions can tamper with this function's state, things could go wrong), and at the same time you can't define the variable inside the function because each time you call it that variable would be reset.
A closure is effectively simply for locking variables in an immediate scope. The easiest example is probably a toggle:
var lightSwitch = ( function closure(){
var isLightOn = false;
return function flickLightSwitch(){
isLightOn = !isLightOn;
alert( isLightOn );
}
}() );
Imagine you're in a badly lit room, where you can't tell if the light is on or off except by flicking the switch to see the difference. When the code is executed, the closure function runs immediately, assigning the value false to isLightOn and assigning the function flickLightSwitch to the variable lightSwitch at the top. Now whenever the flickLightSwitch function is executed (called by the variable it's assigned to, lightSwitch), isLightOn becomes the opposite of whatever it used to be, and the user is alerted of its new value. External code can't read or modify the value of isLightOn because it's 'locked' in the closure function.
Related
I don't know the best way to explain this in words so here is an example of my question:
http://jsfiddle.net/efZyt/
(iframe source is here: http://jsfiddle.net/H6rLQ/ )
Click the 'Change Source' button.
Type something into the input.
Repeat this a few times.
Click on the Repeat Text button.
You will get an alert that will read back to you the text that you typed into the box each step of the way.
I'm a bit confused how the callback function
function(){ alert($('#getSomeText').val()); }
gets loaded into the callback array prior to the text value existing, the function gets called after the value no longer exists (or rather, exists somewhere I can't find) and yet it is able to produce all the values.
I can't figure out where the values are being held for the callback to access them. Does the whole instance of the iframe get preserved as a closure context somewhere for the callback to run in or something?
The is the beauty of JavaScript. The value is not being store anywhere as you would think!
This is the magic of 'closures'.
Closure is basically the concept of a variable being alive even after it's scope has ended.
For example:
function outerFunction() {
innerVar = function innerFunction() {
alert('hello');
}
return innerVar;
}
var outterVar = outerFunction();
outterVar();
The above will output 'hello'. Note, the outerFunction has finished executing and the scope of 'innerVar' is also over; however, interestingly we can still execute a function defined in the outer function.
Similarly, when you pass a function to parent.register, you are NOT passing the actual value obtained by 'val()'; you are passing a function which will later be executed and internally will act as a a closure.
When it does get executed, it then takes the value by using 'val()' of the element present inside that 'closure' function.
I'm making headway on understanding closures, but I don't understand how the following example even creates a closure. I'll quote a passage from 'Learning jQuery', page 392, and what the author says about the example.
The author says that because "readyVar persists between calls to the function", we can see a closure is involved. But, to me, readyVar persists between calls to innerFn simply because the anonymous function has not yet finished executing. Once the anonymous function finishes, there will be no references to readyVar and it will be garbage collected. So where is the closure? I'm under the impression that a closure involves a variable being referenceable in a scope outside of that scope in which the variable was defined. But I don't see that here.
Is the author saying that anytime an inner function references a value defined in an outer function, a closure is created? That can't be what he's saying, can it?
The rest of this message is a quotation from the aforementioned book.
$(document).ready(function() {
var readyVar = 0;
function innerFn() {
readyVar++;
$('#example-9').print('readyVar = ' + readyVar);
}
innerFn();
innerFn();
});
This looks like many of our earlier examples, except that in this case, the outer function is the callback passed to $(document).ready(). Since innerFn() is defined inside of it, and refers to readyVar which is in the scope of the callback function, innerFn() and its environment create a closure. We can see this by noting that the value of readyVar persists between calls to the function:
readyVar = 1
readyVar = 2
For the duration of the $(document).ready function, all it's local variables are active and hold their values and any code in that function or any embedded functions can reference them. While one could describe this as a function closure, this is more just how local variables work in a function.
If, inside the $(document).ready, there was an embedded function that stored a reference somewhere (like a click handler), then a lasting function closure would be established and the value of readyVar would last as long as any embedded references last. It's essentially garbage collection. As long as something outside the function loop holds a reference to something inside the loop, the loop stays alive. At the point where the loop is done executing and nothing outside the loop holds any embedded function references to things inside the loop, the loop gets garbage collected and goes away.
Since there are not embedded function references in what you have now, it will get garbage collected (e.g. destroyed and freed) when it finishes executing.
Now, if you modified it to add a click handler like this, then you now have a lasting reference to a function inside the $(document).ready function with the click handler function. Since that lives on, even after the $(document).ready loop has finished executing, it will not be garbage collected and will live on as a function closure.
$(document).ready(function() {
var readyVar = 0;
function innerFn() {
readyVar++;
$('#example-9').print('readyVar = ' + readyVar);
}
innerFn();
innerFn();
$("#content").click(function(){ // external reference to within this function
alert(readyVar);
});
});
I sense from your question that you're confusing local variables with function closures. The two are related, but not the same thing. Local variables are always available for the lifetime of the function. The lifetime of the function is the time it's executing except when a reference to a closure within it causes it to last longer than that.
You might find this helpful: http://blog.morrisjohns.com/javascript_closures_for_dummies.html
I have this function that populates the currsong variable with data.
The problem is that the variable currsong is only available inside the function and I need to access it globally.
// get a single audio url
echonest.artist(artist).audio( function(audioCollection) {
var currsong = audioCollection.data.audio[0].url;
return currsong;
});
Thank you!
To declare a global variable, you can always remove var:
currsong = audioCollection.data.audio[0].url;
I'm not sure if a global variable is a good solution for whatever you're trying to do, though. People suggest to avoid them for reason.
edit
An example.
Note, the variable will be undefined before function is executed first time. In your code, you only pass it into audio, you don't actually invoke it.
edit2
As Tgr notes, you can also declare global variable explicitly: window.currsong = .... There's no functional difference, but it improves code quality.
Scope is an interesting bird in javascript. So is closure.
Observation 1: you are returning a value from an inline function; that return value is meaningless.
Observation 2: by using the "var" keyword, you are specifying a local scope. Removing var will make the variable global. However, even if you do that it is possible that you will attempt to access that variable before the function gets triggered (i.e. it will be undefined).
Since you're just starting to wrap your head around the concept of closure and javascript scope, I'd recommend reading up on it and then rethinking your application design (since I would be willing to bet that you will learn something which prompts another approach).
In the mean time, try defining the variable outside of the inline function and giving it a temporary value. After that remove "var" from inside of the function.
// get a single audio url
var currsong = "temporary value";
echonest.artist(artist).audio( function(audioCollection) {
currsong = audioCollection.data.audio[0].url;
return currsong;
});
I've rewritten your code to make it a little more clear for myself and others. Please let me know if I've transliterated something incorrectly.
Basically, it looks like you're trying to get curSong as follows:
echonest.artist(artist).audio(
function(audioCollection){
var curSong = audioCollection.data.audio[0].url;
return curSong;
}
);
Right now, what you're doing is passing a function (the anonymous function defined by function(audioCollection)) to the audio function of whatever artist(artist) returns. As such, the curSong value is returned to audio(), and then only when audio() actually runs the function that its handed. I would look at audio() and try to see if there is a way to get curSong out of it. Otherwise, I'd do as slifty describes above and declare curSong in a larger scope, so that it can be accessed even outside of audio().
EDIT: For example, a sample audio function could be as follows:
function audio(inputFunction){
var audioCollection = getAudioCollection();
var song = inputFunction(audioCollection);
return song;
}
The variable curSong is in an anonymous function being passed to audio(). As such, it doesn't exist until that anonymous function is executed, as in the above code. Now, when you run your code (from the first snippet), the anonymous inner function will return curSong to audio(), and audio() will return curSong to you.
When we have code like:
function a(){
var x =0;
this.add=function(){
alert(x++);
}
}
var test = new a();
test.add(); // alert 0
test.add(); // alert 1
test.add(); // alert 2
How does this work?
Doesn't that the value of 'x' in a() should be 'gone' as soon as test = new a() is complete? The stack contains x should also be gone as well, right? Or, does javascript always keep all the stacks ever created in case they will be referenced in future? But that wouldn't be nice, would it...?
The word you're looking for is “closure”.
Creating a function inside another function gives the inner function a (hidden) reference to the local scope in which the outer function was running.
As long as you keep a copy of your test, that has an explicit reference to the add function, and that function has an implicit reference to the scope created when calling the a constructor-function. That scope has an explicit reference to x, and any other local variables defined in the function. (That includes the this value and the constructor's arguments — though you can't access them from inside add as that function's own this/arguments are shadowing them.)
When you let go of test, the JavaScript interpreter can let go of x, because there's no way to get a reference back to that variable.
What you're seeing is the effect of a closure. The function being defined within the other function gets access to all of the variables and such in scope where it is — even after the outer function returns. More here, but basically, the variables (and arguments) in the function all exist as properties on an object (called the "variable object") related to that function call. Because the function you've bound to this.add is defined within that context, it has an enduring reference to that object, preventing the object from being garbage-collected, which means that that function can continue to access those properties (e.g., the variables and arguments to the function).
You normally hear people saying that the function closes over the x variable, but it's more complex (and interesting) than that. It's the access to the variable object that endures. This has implications. For instance:
function foo() {
var bigarray;
var x;
bigarray = /* create a massive array consuming memory */;
document.getElementById('foo').addEventListener('click', function() {
++x;
alert(x);
});
}
At first glance, we see that the click handler only ever uses x. So it only has a reference to x, right?
Wrong, the reference is to the variable object, which contains x and bigarray. So bigarray's contents will stick around as well, even though the function doesn't use them. This isn't a problem (and it's frequently useful), but it emphasizes the underlying mechanism. (And if you really don't need bigarray's contents within the click handler, you might want to do bigarray = undefined; before returning from foo just so the contents are released.)
i am wondering if i can do some cleanup routines that will auto grab timeouts / intervals. consider this:
var timeout = setInterval(function dimitar() {
console.log("hi!");
}, 1000);
console.log(window);
i had a look through window and can't find any reference to the function that's been passed on. the reference to timeout is there, sure enough. so where does the function 'live' here? is it launching a new instance of the js interpreter to eval/run/keep the code? how can you access it in relation to the timeout uid?
i know i can curry the setInterval function and get it to always store the reference into an array which i can then loop through and clear, but am curious if there's a natural way of doing this
The function you create in your example is using a named function expression. The name is only available within the function. Otherwise, it behaves the same as an anonymous function: you haven't assigned it to a variable and since it's not a function declaration, it doesn't create a dimitar variable in the enclosing scope. The following article may be useful: http://yura.thinkweb2.com/named-function-expressions/
There's no eval-type thing going on: you've just passed in a reference to a function into window.setInterval. This function cannot be retrieved afterwards unless you've assigned it to a variable previously, or it was a reference to a function defined by a function declaration.
If you want to keep a reference to the function around, it's simply a matter of storing it in a variable first:
var dimitar = function() {
console.log("hi!");
};
window.setInterval(dimitar, 1000);
so where does the function 'live' here?
The timeout/interval queue is an internal implementation detail that's not accessible to content JavaScript. It retains a reference to the function passed in to setInterval, but it's not a reference that's visible to you.
Incidentally you should generally avoid using named inline function expressions. Although it's probably OK in this example code, IE's JScript has some serious basic bugs with them that can trip you up if you're not careful. Stick to named function statements (function dimitar() { ... } ... setInterval(dimitar, 1000)) or anonymous inline function expressions (setInterval(function() { ... })).
is it launching a new instance of the js interpreter to eval/run/keep the code?
No, it's the same interpreter and the queue could even be implemented in JavaScript. But the variables behind it are hidden away from the caller.
how can you access it in relation to the timeout uid?
The timeout ID is by design completely opaque. The only defined interface that can do anything with it is the clearTimeout/clearInterval call. There is no interface provided to get the function back from a timeout ID.