I'm trying to expand my modest level of JavaScript skills by learning how to use closures. In the code below, I thought I'd see console.log output counting down from 3 to 0. Instead, I'm getting -1, -1, -1, -1.
I know I'm dealing with scoping issues, but that's about it. What's missing? How should this be properly written, and why?
function closure_count_test (number)
{
for (var x = 0; x <= number; x += 1)
{
setTimeout(function() {console.log(number - x);}, x * 1000);
}
}
closure_count_test(3);
Your logic is correct. The problem is that setTimout only considers the latest value of the variables. So the setTimout always get x = 0 since it is the last in the loop.
you can see your desired output if you remove the setTimout function.
x is iterated by the for loop, but the function in setTimeout uses the variable x, which is not interpolated at the time the function is created. This causes it to use whatever the final value of x is (because the setTimeouts execute after the loop completes).
In order to get around this, you have to pass the value of x as it is to the callback of setTimeout. You can call a function that returns another function (the new callback):
for (var x = 0; x <= number; x += 1) {
setTimeout(
(function (x) {
return function () { console.log(number - x) };
})(x)
, x * 1000);
}
This passes x from the outer scope with its current value to the inner scope. The inner function uses whatever value x was when the function was created.
A function is returned to work properly with setTimeout.
http://jsfiddle.net/ExplosionPIlls/QhA3a/
How scoping works in basic words is, it makes variables of a main function, that are referenced in nested functions stay after function ends, and all of these functions can later access them.
In provided example x is a variable defined in the main function, and all nested functions will later be able to reference it. By that time the value of x will be number+1, so your result makes perfect sense. To workaround that, you must avoid referencing the variable of the main function. Here's the normal technique:
function closure_count_test (number)
{
for (var x = 0; x <= number; x += 1)
{
setTimeout(function(x) {
return function() {console.log(number - x);}
} (x), x * 1000);
}
}
What you do here, is you call several nested functions, which have their own x copied as an argument, and each of these have one nested function that will reference that argument via scope.
this works because x being to be localised inside one more closure
function closure_count_test(number) {
for (var x = 0; x <= number; x++) ( // not need {} as here is only one operator
function (x) { //Now x - local variable in anonymous function
return setTimeout(function () {
console.log(number - x);
}, x * 1000);
}(x) // pass x to anonymous function as argument
);
}
closure_count_test(3);
Related
I'm trying to wrap my head around the return statement but I can't see a reason why I should use one. My code works just fine without using one...
In both examples my console prints out 10 not matter if I use return or not.
Without return:
var sum = 5;
function myFunction() {
sum += 5;
}
myFunction();
console.log(sum);
With return:
var sum = 5;
function myFunction() {
return sum += 5;
}
myFunction();
console.log(sum);
By default, functions return the value undefined. If you want the function to return some other value, you need to have a return statement.
You may also use a return statement to halt execution of the function based on some logic, again returning a value that has some meaning or just undefined.
In the first example in the OP, the function is called and the return value is not used for anything, so it doesn't matter what the return value is and a return statement isn't necessary.
In another scenario, the return value might be important, e.g. a function that generates an integer random number between 0 and 10:
function getRandomInteger(){
return Math.floor(Math.random() * 11);
}
function showRandomNumber() {
document.getElementById('s0').textContent = getRandomInteger();
}
<button onclick="showRandomNumber()">Show random number</button>
<span id="s0"></span>
In the above, the getRandomInteger function needs to return a specific value, so it uses a return statement. The showRandomNumber function just displays the random number, so it doesn't need a return statement as the caller (the listener on the button) doesn't care what the return value is.
Here is what is happening with your example:
var sum = 5; //Sets the sum to =5
function myFunction() {
return sum += 5; // += reassigns the global (sum) to 10
}
myFunction();
console.log(sum);
A better example would be this:
sum = 5;
function myFunction() {
var sumOther = sum + 5;
return sumOther;
}
console.log(“sum:” + sum); // 5
console.log(“myFunction:” + myFunction()); // 10
This is how you would get the run of the function and not the global variable ‘sum’
This is because you use (global) variable declared outside the function (function modify it directly so there is no need to return value). However it is not good way of write functions because they are less reusable because they need proper global context to be used. Better is to use something like this:
function myFunction(num) {
return num += 5;
}
var sum = 5;
var result = myFunction(5) ;
console.log(result); // -> 10
this function can be easily used ind different context because it have parameter num and works only on it (function uses only values declared inside its declaration and body)
The trick in your case a is scope of a function. In both cases variable sum is defined in global scope. When you calling the function, it goes through the following steps:
Look whether var sum is defined in current step Since it not defined
inside the function, go one step over and take a look into outer
scope. Yes, it is defined here, start using it.
Perform calculation.
You are using incremental operator sum += 5 so actually it can be
written as sum = sum + 5. If you will look into second case,
you'll notice that variable have increased value now. And since that
variable is taken from global scope, your function just mutates it.
NOTE: At this point no matter whether you are returning something
from function or not. Your function just mutated outer variable.
The last step - exit from function. As I said earlier, return value
matters only if you want to use result of function call directly,
for instance: var result = myFunction()
I'd like to understand the debugging content during the execution of the following code:
var z = 2;
var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);
var x = 3;
console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);
var squareoftwoplusother = (SQUAREPLUSOTHER)(x);
x = 4;
z = 4;
var result = squareoftwoplusother(5);
console.log("result", result);
Now....
At the call of:
console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);
the debug shows clearly:
squareoftwoplusother: undefined
SQUAREPLUSOTHER: x=>...
x: 3
z: 2
at the following call of:
var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);
the debug shows:
Local:
x: 3
Closure
z: 2
at the following call of:
x = 4;
z = 4;
the debug shows:
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
x: 4
z: 4
at the following call of:
var result = squareoftwoplusother(5);
the debug shows:
result: 18
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
Local:
x: 5
Closure
x: 3
Closure
z: 4
and at the final calls the debug shows:
result: 18
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
x: 4
z: 4
now the questions:
How many "Closures"? They belongs to? (i.e. how to explain...)
Local:
x: 5
Closure
x: 3
Closure
z: 4
How the scope of the variables is managed in javascript?
How to have a "definitive" idea in terms of "context" or "whatever it be" about the mess of closure :-)?
thanks in advance
Ed
Every time a function is called, a local scope is created for that function. If there is still a reference to that local scope after the function returns, then a closure is created. Once the reference is gone, the closure is also garbage collected.
If you add breakpoints to the first line of every function, you will see that scopes are created that may later become closures.
A great explanation is given here http://dmitrysoshnikov.com/ecmascript/javascript-the-core/#activation-object
I'll add some braces to your code to make that easier and I'll add self calling function to add a level of closures.
(() => {
var z = 2;
var SQUAREPLUSOTHER = (x) => {
debugger;
return (y) => {
debugger;
return (x * x) + y + z;
}
};
var x = 3;
console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);
var squareoftwoplusother = (SQUAREPLUSOTHER)(x);
x = 4;
z = 4;
var result = squareoftwoplusother(5);
console.log("result", result);
debugger
})()
The screenshots below are from Chrome DevTools which minimizes the closures, that is, it only maintains references to what is needed. Back in the days, the entire closure was always available and you could prove it because it showed up in the closures pane of debuggers. See Javascript closures performance for further details
Scope
There are just three different scopes in your code. One is the global scope all variables you declare in and the other two are here:
var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);
There are two function scopes, one containing the variable x and the other function scope containing the variable y. It might be easier to see if you replace the arrow function with functions:
// global scope
function SQUAREPLUSOTHER(x) {
// function scope containing x
return function(y) {
// function scope containing y
return (x*x) + y + z;
};
}
How scoping works is actually quite simple:
Every { starts a new scope and its counter } closes it, variables declared inside it with let and const (or var but thats slightly more complicated) are part of the scope. If it is the scope of a function, the parameters (e.g. x and y) are part of that scope.
From the code, you can access the all variables that are in the current scope or in its parent scope, if there are multiple with the same name you get the most inner one. Therefore x inside of the SQUAREPLUSOTHER function refers to the variable of the SQUAREPLUSOTHER scope, while for code outside of it x is the global variable and the functions variable can't be accessed.
The Scope of a variable does not change at runtime, you can always directly see which scope a variable belongs tp by looking at the surrounding { .. }.
Now different variables in different scopes have to hold values at runtime, thats where we get to:
the environment record
When you call a function, the JavaScript engine creates a new "EnvironmentRecord" (which is like an internal object) that contains all the variables of the function you call, e.g. in this case:
function test(a) {
let b;
}
Then if you call that function (test(1)) a new environment record gets created that contains a and b. Now the code inside the function gets run, and every variable is looked up in it. If there are two functions nested into another, calling the inner function will create an environment record that holds a reference to the outer one:
function test(a) {
function test2(b) {
}
test2(5);
}
Now calling test(1) will create an record where a is 1. If the engine then executes the second call (test2(5)) it creates another record containing b being 5, and that holds a reference to the record containing a. Now if you use a inside test2, the engine will look it up in the current environment record, won't find it, and then look it up in the parent where it finds a being 1.
closure
Usually those records get deleted when the execution reaches the }, however if there is another record that got the current record as a parent, it won't get deleted. It will exist until all child records got deleted, then it will also remove the parent. This behaviour (variables live longer because they can be accessed from an inner functions body) is called a closure.
The W3Schools example for a JS for-each loop (http://www.w3schools.com/js/js_loop_for.asp) is
var person = {fname:"John", lname:"Doe", age:25};
var text = "";
var x;
for (x in person) {
text += person[x];
}
and I'm wondering if there's any particular reason why x is defined outside of the loop if it's only used inside the loop in that particular example, or if that's necessary condition for defining a for-each loop, and if so, why?
This is(/was) an old convention, meant largely to indicate that x does not exist only inside the loop.
Declaring variables at the top of a function is not necessary and is variously encouraged/discouraged by different style tools. It can be convenient to group variable declarations in one place, but may increase the distance between declaration and use (generally considered a bad thing).
In JS, the var declaration works at function-scope, so variables are hoisted to the top of the nearest function and live for the duration of the function. See:
function foo() {
for (var i = 19; i > 0; --i) {
console.log(typeof i); // number
}
console.log(typeof i); // number
}
foo();
Because the variable is accessible throughout the function, it is declared at the start of the function (C used to require this).
ES6 has changed this with the let statement, which introduces the more common block-level scoping. With let, the variable is only available inside of the loop:
function foo() {
for (let i = 19; i > 0; --i) {
console.log(typeof i); // number
}
console.log(typeof i); // undefined
}
Can someone please explain how this gets 50, and how does the algorithm works. Thanks.
var multipliers = function makeMultipliers (max) {
var result = [];
for (var i = 0; i < max; i++)
result.push (function (x) {return x * i;});
return result;
}
multipliers(10) [2] (5)
???
what’s the value?
50, not 5
can you fix it?
Source: http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-170-software-studio-spring-2013/lecture-notes/MIT6_170S13_35-java-fn-cls.pdf
page 30
It's a scope issue. By the time the last function is called, i is where it was last seen at that scope last which would be 10. You can prevent this with a closure.
function multipliers(max){
var a = [];
for(var i=0; i<max; i++){
(function(i){
a.push(function(x){return x*i});
})(i);
}
return a;
}
In this case, the closure is a self-executing function that scopes off i at each step of the loop. If this did not happen the scope would go to the multipliers function itself. Since the loop has already completed by the time you are calling the function which you pass 5 to, which happens to be at step 2 of the Array that multipliers returns, i has already reached 10. Obviously, 10*5 is 50. When the closure is used is last position is 2 within the scope it is in, giving you the result that is sought. 5*2 = 10.
console.log(multipliers(10)[2](5));
This code creates an array of functions which will incorrectly all end up referring to the final value of i, but which are intended to freeze the value of i during each iteration.
To fix it you simply could add a level of locality to the iteration variable by embedding a new local variable that freezes the value of i within another function. For example, below the existing local variable i is passed into the dummy function as an argument, and the value of i at that instant is frozen into the new local variable i which is independent of the original i and not changed by the subsequent iterations of the original i.
result.push (function (x) {return x * i;})
result.push((function(i) {
return function (x) {return x * i;};
})(i));
Here's the example code I'm struggling with:
function greaterThan(x) {
return function(y) {
return y > x;
};
}
var greaterThanTen = greaterThan(10);
show(greaterThanTen(9));
Is there a way to put it in math terms or follow the flow or something? I don't know why 10 is x and 9 is y.
In the line:
var greaterThanTen = greaterThan(10);
You are assinging the variable x to the value 10 and then you store the function in the greaterThanTen Variable to be called later. this means that:
greaterThanTen = function(y) {
return y > 10;
};
So when you do:
greaterThanTen(9); #y = 9
You are calling:
return 9 > 10;
This function doesn't call a function, it returns a function.
This code is creating a new unary function where the original binary (greater than) operator's right-hand operand is prebound to a specific value.
In lambda calculus this binding is known as currying.
In Javascript the binding happens because the supplied value of the parameter x in greaterThan is permanently retained in the scope of the inner function (or "closure") that is returned.
So, when you call:
var greaterThanTen = greaterThan(10);
what you now have is a new function (named greaterThanTen) which always compares its single parameter to the bound value of 10.
Hence:
greaterThanTen(9);
will return false.
Create greaterThan(10)
Create function:
function(y){return y > x}
return function.
So, when you call greaterThan(10), the function returns a function whose local variable x is set to 10.
var greaterThanTen = greaterThan(10) equals:
var greaterThanTen = function(y){return y > 10};
To finish, greaterThanTen(9) is called, which equals 9 > 10, which is false.
The only thing that greaterThan does is to set a value for x in
function(y) {return (y>x);}
and store the resulting function in a variable name, in this case greaterThanTen, now with the contents
function(y) {return (y>10);}
Calling greaterThanTen(9) is the same as looking at
function(y = 9) {return (y>10);}
which is the same as
function(y = 9) {return (9>10);}
which is false. Hence false is returned.
Edit:
Example of function that returns a function here: http://i.imgur.com/aiHSH.jpg (x and y is switched around in y>x)
Namaste
The greaterThanTen variable represents a function taking one argument and returning a boolean value whether this argument is greater then 10.