Javascript closure not working
That's rather useless, because the… var i …
async(function() { …
// errorLogging(tx, error, id);
(function(a, b, c) {
errorLogging(a, b, idsArray[c]);
})(tx, error, i);
… })
i
variable already does have the wrong values there. You need to put the wrapper around the whole async callback, closing over all variables are used within the async callback but are going to be modified by the synchronous loop.The easiest way (works always) is to simply wrap the complete loop body, and close over the iteration variable:
for (var i = 0; i < paramsArray.length; i++) (function(i) { // here
var query = queryArray[i];
var params = paramsArray[i];
var id = idsArray[i];
window.logger.logIt("id: " + id);
tx.executeSql(query, params, function (tx, results) {
incrementSyncDownloadCount(results.rowsAffected);
}, function(tx, error) {
if (error.message.indexOf("are not unique") > 0 || error.message.indexOf("is not unique") > 0) {
incrementDuplicateRecordCount(1);
return false;
}
errorLogging(tx, error, id);
return true;
});
}(i)); // and here
You also might pass all variables that are constructed in the loop (and depend on the iteration variable) as the closure arguments. In your case, it might look like this:for (var i = 0; i < paramsArray.length; i++) {
(function(query, params, id) { // here
window.logger.logIt("id: " + id);
tx.executeSql(query, params, function (tx, results) {
incrementSyncDownloadCount(results.rowsAffected);
}, function(tx, error) {
if (error.message.indexOf("are not unique") > 0 || error.message.indexOf("is not unique") > 0) {
incrementDuplicateRecordCount(1);
return false;
}
errorLogging(tx, error, id);
return true;
});
}(queryArray[i], paramsArray[i], idsArray[i])); // here
}
Or you identify the async callback, and wrap only that:for (var i = 0; i < paramsArray.length; i++) {
window.logger.logIt("id: " + idsArray[i]);
tx.executeSql(queryArray[i], paramsArray[i], function (tx, results) {
incrementSyncDownloadCount(results.rowsAffected);
}, (function(id) { // here
return function(tx, error) {
// ^^^^^^ and here
if (error.message.indexOf("are not unique") > 0 || error.message.indexOf("is not unique") > 0) {
incrementDuplicateRecordCount(1);
return false;
}
errorLogging(tx, error, id);
return true;
};
}(idsArray[i]))); // and here
}
JavaScript closure inside loops – simple practical example
Well, the problem is that the variable i
, within each of your anonymous functions, is bound to the same variable outside of the function.
ES6 solution: let
ECMAScript 6 (ES6) introduces new let
and const
keywords that are scoped differently than var
-based variables. For example, in a loop with a let
-based index, each iteration through the loop will have a new variable i
with loop scope, so your code would work as you expect. There are many resources, but I'd recommend 2ality's block-scoping post as a great source of information.for (let i = 0; i < 3; i++) {
funcs[i] = function() {
console.log("My value: " + i);
};
}
Beware, though, that IE9-IE11 and Edge prior to Edge 14 support let
but get the above wrong (they don't create a new i
each time, so all the functions above would log 3 like they would if we used var
). Edge 14 finally gets it right.ES5.1 solution: forEach
With the relatively widespread availability of theArray.prototype.forEach
function (in 2015), it's worth noting that in those situations involving iteration primarily over an array of values, .forEach()
provides a clean, natural way to get a distinct closure for every iteration. That is, assuming you've got some sort of array containing values (DOM references, objects, whatever), and the problem arises of setting up callbacks specific to each element, you can do this:var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
// ... code code code for this one element
someAsynchronousFunction(arrayElement, function() {
arrayElement.doSomething();
});
});
The idea is that each invocation of the callback function used with the .forEach
loop will be its own closure. The parameter passed in to that handler is the array element specific to that particular step of the iteration. If it's used in an asynchronous callback, it won't collide with any of the other callbacks established at other steps of the iteration.If you happen to be working in jQuery, the $.each()
function gives you a similar capability.
Classic solution: Closures
What you want to do is bind the variable within each function to a separate, unchanging value outside of the function:var funcs = [];
function createfunc(i) {
return function() {
console.log("My value: " + i);
};
}
for (var i = 0; i < 3; i++) {
funcs[i] = createfunc(i);
}
for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}
problems with closure in JS
Line:1 invokes level1
fn and get back fn level2
stored in alias temp
.
Line:2 invokes temp
fn and get back fn level3
stored in alias temp2
.
Line:3 now when invoking temp2
fn you execute fn level3
getting back the result of addition operation.
So temp3
is not a function but a value.
var a = 10;
function level1(b) { var c = 1;
function level2(f) { var d = 2;
function level3(g) { return a + b + c + d + f + g; } return level3; } return level2;}var temp = level1(10);var temp2 = temp(10);var temp3 = temp2(10);console.log(temp3); // or level(10)(); without variable
javascript closure, not working?
Well, the first function, returns a function, and you want the inner function to be executed.
If you invoke the result of it you will see it work, e.g.:
getZone()();
I think you want the following, use an immediately executed anonymous function, to call the $find
method only once, storing its result:var getZone = (function() {
var slidingZone = $find("<%= slidingZone.ClientID %>");
return function () { return slidingZone; };
})();
How do JavaScript closures work?
A closure is a pairing of:
- A function and
- A reference to that function's outer scope (lexical environment)
Every function in JavaScript maintains a reference to its outer lexical environment. This reference is used to configure the execution context created when a function is invoked. This reference enables code inside the function to "see" variables declared outside the function, regardless of when and where the function is called.
If a function was called by a function, which in turn was called by another function, then a chain of references to outer lexical environments is created. This chain is called the scope chain.
In the following code, inner
forms a closure with the lexical environment of the execution context created when foo
is invoked, closing over variable secret
:
function foo() {
const secret = Math.trunc(Math.random() * 100)
return function inner() {
console.log(`The secret number is ${secret}.`)
}
}
const f = foo() // `secret` is not directly accessible from outside `foo`
f() // The only way to retrieve `secret`, is to invoke `f`
Javascript - Error ... is not a function inside a closure
Inside the onclick
, this
will be a reference to the DOM element that was clicked, not what this
means where you're hooking it up.
If you want to access the object this
refers to when you're setting up the handler, use a variable:
var thisObj = this;
for (...) {
...and then in the handler:thisObj.displayImg(tags[x]);
Although in this case, since you don't need this
to refer to the handler, you can make it a lot simpler with Function#bind
:for (var i = 0; i < tags.length; i++) {
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML = tags[i];
li.onclick = function(x) {
console.log(tags[x]);
this.displayImg(tags[x]);
}.bind(this, i);
}
Function#bind
returns a new function that, when called, will call the original with a specific this
value and any further arguments you give bind
(followed by any arguments it receives at runtime).Side note: You may as well just pass the tag in, rather than the index:
var thisObj = this;
for (var i = 0; i < tags.length; i++) {
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML = tags[i];
li.onclick = (function(tag) {
return function() {
console.log(tag);
thisObj.displayImg(tag);
};
})(tags[i]);
}
orfor (var i = 0; i < tags.length; i++) {
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML = tags[i];
li.onclick = function(tag) {
console.log(tag);
this.displayImg(tag);
}.bind(this, tags[i]);
}
Closure in node js not working as expected
var j = i;
will set the value of i
which is length of the array on first response and that is the reason you get 2
every time you log it.
Invoke a anonymous function as a second argument of http.get
which will return inner function to handle response and it will also remember the environment in which it is created. Value of passed argument i
will be there in the memory to be used later.
Try this:
var http = require("http");
var urls = ["http://yahoo.com", "http://google.com"];
for (var i = 0; i < urls.length; i++) { http.get(urls[i], (function(i) { return function(res) { res.setEncoding('utf-8'); res.on("data", function(d) { console.log(i); }); } })(i));}
Closure not working outside of the function scope
var later;
function outerFunc() {
var innerVar = "Inside Outer";
function innerFunc() {
console.log(innerVar);
}
later = innerFunc;
};
outerFunc(); //Don't run innerFunc, just set later = innerFunc
later(); // Execute innerFunc
So it logs it just one time.. It seems nice..
Related Topics
How to Bind Bootstrap Popover on Dynamic Elements
Removing Duplicate Objects with Underscore for JavaScript
Find the Exact Height and Width of the Viewport in a Cross-Browser Way (No Prototype/Jquery)
How to Calculate How Many Seconds Between Two Dates
Fix the Upstream Dependency Conflict Installing Npm Packages
Understanding JavaScript Promise Object
Select a Complete Table with JavaScript (To Be Copied to Clipboard)
How to Pass JavaScript Variables as Parameters to Jsf Action Method
JavaScript Strings Outside of the Bmp
Uncaught Typeerror: Cannot Use 'In' Operator to Search for 'Length' In
Jquery Returning "Parsererror" for Ajax Request
Unexpected Token Illegal in Webkit
Why Does a Simple .*? Non-Greedy Regex Greedily Include Additional Characters Before a Match
External Resource Not Being Loaded by Angularjs
Differencebetween Native Objects and Host Objects