This question already has answers here:
standalone parentheses in javascript [duplicate]
(5 answers)
Closed 8 years ago.
I am studying JavaScript and I sometimes see something like this
function functionname()
{
// Some statements
} () ;
What does () following } mean?
Thanks a lot, experts on Stack Overflow
That is an IIFE (immediately invoked function expression). It is used to create a new scope. For example:
var x = 10;
(function() {
var x = 5;
}());
alert(x); // still 10
All it does is define and call the function at the same time.
IIFEs are also used to "save" the value of a variable. For example, this code won't work:
for (var i = 0; i < buttons.length; i ++) {
buttons[i].onclick = function() { alert(i) }
}
Every button will alert the last index when you click it, because after the loop is done i is buttons.length. To fix it, you would use an IIFE:
for (var i = 0; i < buttons.length; i ++) {
buttons[i].onclick = (function(i) {
return function() {
alert(i)
}
})(i)
}
More info on IIFEs
It calls the function.
var foo = function () { return 1; }();
alert(foo); // 1
There are lots of ways to define a function, when you do it like this ...
(function functionname(innerArguments){
// Some statements;
})(outerArguments);
... the function is executed as soon as this piece of code is interpreted;
its the same as:
function functionname(innerArguments){
// Some statements;
};
functionname(outerArguments);
Related
This question already has answers here:
TypeError: console.log(...) is not a function [duplicate]
(6 answers)
Closed 3 years ago.
this code doesn't work
for (let i = 0; i < 10; i++) {
console.log("ddd")
(function x() {
console.log("eee")
})();
}
VM531:3 Uncaught TypeError: console.log(...) is not a function
at :3:3
these two works just fine
for (let i = 0; i < 10; i++) {
(function x() {
console.log("eee")
})()
console.log("ddd")
}
for (let i = 0; i < 10; i++) {
(function x() {
console.log("eee")
})()
}
You need to have a semicolon after the console.log - otherwise it's trying to call the returned result of console.log (undefined) which isn't a function, which is calling your error.
Automatic semicolon insertion doesn't take into account whitespace.
for (let i = 0; i < 10; i++) {
console.log("ddd");
(function x() {
console.log("eee")
})();
}
Your code was trying to do:
console.log("ddd")(function x() {...})()
Which turns out to be:
undefined(function x() {...})()
Which results in your TypeError.
This problem of brackets overlapping due to a lack of semicolons is similar to my answer on this question.
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
How do JavaScript closures work?
(86 answers)
Closed 7 years ago.
I am confused why the following code snippet has (i) at the end of it:
for (var i = 0; i < 10; i += 1) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 1000);
})(i);
}
Ive seen it in production code Ive worked on--I just can intuit why it's necessary.
You are defining an inline function, so you could force the i parameter to be in the local scope at the time of the execution of the console.log statement. By adding the parameter, you are creating a self executing function. Similar would be the following statements, which might be better to read...
function logmeWithTimeOut(value) {
setTimeout(function() { console.log(value); }, 1000);
}
for (var i = 0; i < 10; i++) {
logmeWithTimeout(i);
}
Though I might prefer
function logmeWithTimeout(value) {
console.log(value);
}
for (var i = 0; i < 10; i++) {
setTimeout(logmeWithTimeout.bind(undefined, i), 1000);
}
It forces the i to be in local scope, otherwise your log would print only 11
Because you are defining a function inside the parenthesis, and then you are calling it passing i as parameter.
If you didn't put the (i) there, you would just define a function but never call it.
This question already has answers here:
Javascript infamous Loop issue? [duplicate]
(5 answers)
Closed 8 years ago.
My understanding of Javascript is that variables have function scope, not block scope, so variables declared inside a block are hoisted to the function above it. This article gives the following code example:
var arr = [1, 2, 3, 4]
for(var i = 0; i < arr.length; i++) {
var entry = arr[i];
setTimeout(function() {
console.log(entry);
}, 100);
}
The article states the the code gets translated into the following, and so the variable entry is common between each iteration. The result is that 4 is logged to the console four times
var arr, i, len, entry;
arr = [1, 2, 3, 4]
for(i = 0; i < arr.length; i++) {
entry = arr[i];
setTimeout(function() {
console.log(entry);
}, 100);
}
My question is, how should I rewrite the code if I want each call to setTimeout to log a different value from arr?
You can change the setTimeout to:
setTimeout(
(function()
{
var entry = arr[i];
return function() {console.log(entry);}
}
)()
);
That way, you create a new scope, and entry is in that scope.
You can also do:
(function(e)
{
setTimeout(function(){console.log(e);});
}
)(entry);
Which also creates a new scope, in which e lies.
Yet another option:
setTimeout(
(function(e)
{
return function() {console.log(e);};
}
)(entry);
);
In all cases, you use an anonymous function that you call immediately, so the only side-effect is that you are creating a new scope.
(edit: reformated a bit for readability, and added a bit more explanations)
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
Here's a simplification of my JS program. mylist is an array of strings and MyAsync is a function that takes an object and arranges for the supplied callback to be called at a later time.
for (var myindex = 0; myindex < mylist.length; myindex += 1) {
MyAsync(mylist[myindex], function () { alert(myindex); });
}
When there's ten items in mylist, the result is two alert messages each showing "10". Okay, it's clearly using the value of myindex after the loop finishes. So I make a slight change...
for (var myindex = 0; myindex < mylist.length; myindex += 1) {
var copyindex = myindex;
MyAsync(mylist[myindex], function () { alert(copyindex); });
}
Now, each alert shows "9".
How do I please arrange for the callback function to know what myindex was at the time MyAsync was invoked?
Asynchronously, billpg.
Yeah, as the comments and not making functions in a loop for the reason you are experiencing.
We can use a recursive function instead :
var len = mylist.length;
function asyncLoop(index) {
MyAsync(mylist[index], function () {
if(index < len) {
asyncLoop(++index);
}
});
}
asyncLoop(0);
As comments , - firing them all off at the same time* ( *- quick as a loop can run ). and keeping track of the array count ...
function asyncDo(index) {
MyAsync(mylist[index], function () {
/* we have access to the array index here */
console.log(index);
});
}
for ( var i=0, len=mylist.length; i<len; ++i) { asyncDo(i); }
You can use closures to do this: here is some code that I think demonstrates what you want, printing out 0 .. 9.
var funcs = [];
for(var i = 0; i < 10; i++){
funcs.push( (function(j){
return function(){
console.log(j);
};
})(i));
}
funcs.forEach(function(f){
f();
});
The idea is that in returning a function to be added to the list, the value of i is captured when that function was constructed from the parameter to the outer function.
Here's an SO post that helped me with this: JavaScript closures vs. anonymous functions
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 9 years ago.
Consider this
fs=[];
for(var i = 0; i < 3; i++){
fs.push(function(){
return i;
});
}
console.log(fs[0](),fs[1](),fs[2]())
I thought that i would be in the closure of the function so that this would print "0 1 2", but nope... it prints "3 3 3".
Why doesn't this work? And is there any way to make this work?
You are actually pushing three instances of the same anonymous function into your 'fs' array. Then your log statement calls that function three times. At the time you are calling it, the loop has completed and the value of 'i' within the closure is 3, so that's what is returned.
I'm not sure what you mean by "work", but maybe something like this is what you mean:
fs = [];
function closureFunc(myVal) {
return function () {
return myVal;
}
}
for (var i = 0; i < 3; i++) {
fs.push(closureFunc(i));
}
console.log(fs[0](), fs[1](), fs[2]());
This creates three separate closures where the function you are pushing has the scope of the declaring function "closureFunc". Within those closures the myVal is set to the value that was passed in.
Javascript doesn't have a notion of block scope, it only has function scope. Hence the placement of the var i is meaningless in terms of lifetime. It may as well have been the first line in the method.
In order to fix this you need to declare a new scope that holds a separate i value
fs=[];
var makeFunc = function(j) { return function() { return j; } }
for(var i = 0; i < 3; i++){
fs.push(makeFunc(i));
}