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));
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()
Chapter 3 Functions has the following code snippet:
const power = function(base, exponent) {
let result = 1;
for(let count = 0; count < exponent; count++) {
result *= base;
}
return result;
};
console.log(power(2, 10));
// 1024
can someone explain what is going on in the code line by line, i'm confused by let result = 1 the most. Thanks!
In the first line, you're declaring a variable result. However, it's being declared with let, not var. Let is similar to var, except it can't be accessed outside the block it is defined in (including functions, loops and conditional statements). And since it's in a function here, that first line is equivalent to:
var result = 1;
In the second line:
for (let count = 0; count < exponent; count++) {}
You're looping over exponent - so the code within the {} of the loop will be executed exponent times.
In the third line:
result *= base;
You're multiplying result and base, and assigning the value to result. This line is equivalent to:
result = result * base;
Final line:
return result;
This line stops the function and returns result. The return means that whenever a function is called, it essentially is replaced with the return value (like in this line):
console.log(power(2, 10));
This calls power() with arguments 2 and 10, and logs the returned value to the console.
This example is a simple approach of building and executing an exponential function in JavaScript.
That said, we know that the below will essentially be creating something like the following in pseudocode:
print the result of (number to the power of some other number)
The code walkthrough:
// initialize a constant variable named 'power' as a function declaration with two arguments, 'base' and 'exponent' which will be used inside the function
const power = function(base, exponent) {
// declare and initialize variable called 'result' and set it with value of 1
// why this is 1, is because any number to the power of 1 is itself, so rather than setting this to 0, this must be 1 to ensure that the exponential function works accurately
let result = 1;
// let count = 0; this will initialize a variable named count to be used within the loop
// count < exponent; this is the conditional statement, it means that the loop will continue looping until the condition is met, meaning loop until 'count' is no longer less than 'exponent'
// count++; this increments the value of the initial variable, in this case 'count' for every trip through the loop for the duration that the condition statement remains true
for (let count = 0; count < exponent; count++) {
// multiply the 'result' variable by the 'base' variable and set it as the new value of the 'result' variable
result *= base;
}
// return the 'result' variable so that it is now available outside of the function
return result;
};
// pass in the 'base' and 'exponent' arguments for the function 'power' in order to get the value (effectively, 2^10), and then print this value to the console
console.log(power(2, 10));
// 1024
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
Say I have this function:
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
setTimeout( function() {
console.log( fruits[i]);
}, i * 1000);
}
}
printFruits(["Lemon", "Orange", "Mango"])
So this returns undefined 3 times.
I can see on a high level that since variables are stored not by value but by reference inside the closure... the loop is finishing first and by the time the functions are dequeued from maybe the Event Loop... the variable is already at undefined (fruits.length evaluates to 3 which is too high for this array size). But why does this perform strangely... it prints "apple" 3 times.
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
var someConstant = i;
setTimeout( function() {
console.log( fruits[someConstant]);
}, someConstant * 100);
}
}
printFruits(["mango", "banana", "apple"])
Shouldn't someConstant be changing as well with i? Why does it seem to be 2 always?
Also this works:
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
(function() {
var current = i;
setTimeout( function() {
console.log( fruits[current]);
}, current * 1000);
})();
}
}
Why is the IIFE necessary to fix this problem?
2nd Example
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
var someConstant = i;
setTimeout(function() {
console.log(fruits[someConstant]);
}, someConstant * 1000);
}
}
printFruits(["Lemon", "Orange", "Mango"])
This logs thrice Mango. Because everytime the someConstant variable is created and re-initialised to i. Recollect how for loop works. i-value is increasing here till 4, checks the condition 4<3, and terminates. So the matter inside the loop executes only thrice. So the last value of someConstant defined in the printFruits functional scope is 2. So when the inner function executes someConstant, its equal to 2. So we get each time Mango.
3rd example
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
(function() {
var current = i;
setTimeout(function() {
console.log(fruits[current]);
}, current * 1000);
})();
}
}
printFruits(["Lemon", "Orange", "Mango"])
Here the beauty of closures happening. Here its a self executing function being executed, immediately. So when i = 1, it invokes immediately. Every function has a different scope now. There is a seperate current value defined for each. So later when it executes, it recollects whats the value of 'current' when it was defined inside its scope.
The only difference between these samples is that the for loop increments i to 3 before stopping, while the last value which is assigned to someConstant is 2. Your "working" code is outputting Mango three times (index 2 of the array) instead of undefined (index 3 of the array). The general behaviour is the same.
Yes, you do need an IIFE, or ES6's let keyword instead of var.
The difference is that someConstant never gets incremented after the last iteration. The for() loop sets i = 3, the test i < fruits.length fails, so the loop stops. As a result, someConstant is still set to 2 from the last iteration of the loop. Then all the callbacks run, so they all log fruits[2], which is Mango.
You need the IIFE to get each iteration to save its value of i in the closure.
While learning about javascript closures, I came across this answer https://stackoverflow.com/a/111111/3886155 on stackoverflow.
It's a very good explanation of closures.
But I have some confusion in Example 4 and Example 5.
I just copy entire snippet here:
Example 4:
var gLogNumber, gIncreaseNumber, gSetNumber;
function setupSomeGlobals() {
// Local variable that ends up within closure
var num = 666;
// Store some references to functions as global variables
gLogNumber = function() { console.log(num); }
gIncreaseNumber = function() { num++; }
gSetNumber = function(x) { num = x; }
}
setupSomeGlobals();
gIncreaseNumber();
gLogNumber(); // 667
gSetNumber(5);
gLogNumber(); // 5
var oldLog = gLogNumber;
setupSomeGlobals();
gLogNumber(); // 666
oldLog() // 5
After reading some examples I can say that whenever function inside the function executes it can always remember the variables declared inside outer function.
I agree that if these closure variable updated anyway it still refers to the new variable value.
My problem in this example is specially related to var oldLog=gLogNumber;
How it can return old number after call to the setupSomeGlobals();?
because now the var num has reset.So why it is not using this new num value 666?
Now Example 5:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + i;
result.push( function() {console.log(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
// Using j only to help prevent confusion -- could use i.
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
Here they have pushed functions into array and executed them after loop finishes.But now reference to the closure variables is the latest one after loop finishes.Why not old one?
In both examples you are just assigning function definition to variable or array index.But first one points to old and second one points to latest.Why?
How it can return old number after call to the setupSomeGlobals()
num is not globally scoped, so the value num is in the context of which reference of gLogNumber is invoked.
After invocation of setupSomeGlobals method again, reference to gLogNumber got changed. try this
console.log(Object.is( gLogNumber, oldLog )); //true
setupSomeGlobals();
console.log(Object.is( gLogNumber, oldLog )); //false
So, oldLog retained old reference and hence old value of num, but gLogNumber got new num.
But now reference to the closure variables is the latest one after
loop finishes.Why not old one?
For this problem, have a look at
JavaScript closure inside loops – simple practical example.
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);