This question already has answers here:
passing index from for loop to ajax callback function (JavaScript)
(3 answers)
Closed 8 years ago.
I'm sure this has been asked before, but I don't know what to search for.
So I want function to be called with a string that corresponds with the item clicked, but I want to simply add any new items to an array of strings.
var menuList = ["overview", "help", "search"];
var functionCalls = [
function() { toggleMenu(menuList[0]); },
function() { toggleMenu(menuList[1]); },
function() { toggleMenu(menuList[2]); },
];
which is used like this in a loop: $("something").click(functionCalls[i])
This is what I want to do (but obviously it doesn't work):
for (var i in menuList) {
// This does not work because the closure references 'i'
// which, at the end, is always the index of the last element
$("something").click(function() {
toggleMenu(menuList[i]);
});
// this works, but I have to define each closure
$("something").click(functionCalls[i]);
}
How can I create an anonymous function that accepts a value based on a variable - but doesn't retain the reference to the variable?
You could use an IIFE like this:
for (var i=0; i<menuList.length; i++) {
!function( index ) {
$("something").click(function() {
toggleMenu( menuList[index] );
});
}( i );
}
By calling the anonymous function, you create a local copy of the current value for i with the name index. Hence, all handlers receive their respective version of i.
Related
This question already has answers here:
Accessing an object property with a dynamically-computed name
(19 answers)
Closed 3 years ago.
i need to return this.
GetBooking = function (parameter) {
return Booking.Title[0].parameter;
}
GetPages = function () {
return GetBooking(pages)
}
GetNumber = function () {
return GetBooking(number)
}
booking is a object of arrays, is possible?
If I understand correctly, when doing GetBooking(pages) you expect to get in return Booking.Title[0].pages, meaning GetBooking() function is supposed to be like a middleman to decide which property you want to get from Booking.Title[0].
If I'm correct, then you almost had it right. What will happen in your code is, for example if number was 7, it would look for a property named 7 inside Booking.Title[0].
What you really want to do is this: return Booking.Title[0][parameter], and parameter has to be a string value representing the property you're looking for, meaning you also need to change the rest of the code which would ultimately look like this:
GetBooking = function (parameter) {
return Booking.Title[0][parameter];
}
GetPages = function () {
return GetBooking("pages") ;
}
GetNumber = function () {
return GetBooking("number") ;
}
This will take the string in parameter and look for a property that matches that string inside Booking.Title[0], and return its value.
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
I have a class in javascript with a property (is_initialized) and a function (isInitialized).
Class definition :
function Test()
{
this.is_initialized = { obj: { isInitialized: 'notyet' } };
this.isInitialized = function( ref )
{
if ( !ref.obj )
{
console.log( 'now: ' + JSON.stringify( this.is_initialized ) );
/*line 9*/ this.is_initialized.obj.isInitialized = ref.isInitialized.toString();
console.log( ref );
}
else {
bluetoothle.isInitialized( this.isInitialized );
/*line 14*/ ref.obj = this.is_initialized.obj;
}
};
}
bluetoothle.isInitialized is a function in a cordova plugin (no knowledge of cordova is required for answering this question), it returns an object { isInitialized : true/false } and will pass the first if-statement whilst my call to isInitialized() will execute the else.
Question :
Why does this.is_initialized on line 9 create a new property inside the function isInitialized while this.is_initialized on line 14 uses the property is_initialized in Test()?
Shouldn't it both use the property inside Test() or use a (new) variable inside isInitialized()?
And if it 'just' behaves like this, what can i do to deal with it?
Code i ran :
var t = new Test();
var r = {obj:{isInitialized:'nope'}};
t.isInitialized(r);
// console.log( 'now: ' + JSON.stringify( this.is_initialized ) ); on line 8:
// now: {"obj":{"isInitialized":"false"}}
// console.log( ref ); on line 10:
// Object {isInitialized: false}
console.log(JSON.stringify(r));
// {"obj":{"isInitialized":"notyet"}}
console.log(JSON.stringify(t));
// {"is_initialized":{"obj":{"isInitialized":"notyet"}}}
What just happened is this:
i made a new instance of Test() and named it t.
i made an object with matching structure of is_initialized in Test() but with a different value.
i called the function with r as parameter.
code in the else executes.
asynchronous function with isInitialized as callback is called.
the function created a reference between the existing is_initialized and r.
the async function calls isInitialized and executes the code in the if.
it logs the current value of this.is_initialized on line 8, somehow it gets this.is_initialized after line 9 is executed.
line 9 executes, creating a new variable named is_initialized inside isInitialized() while i want it to set is_initialized in Test() and not create a new variable that dies when the function is done executing.
it logs the object that was put into this.is_initialized.obj.isInitialized.
i log r and see that it contains the initial value of Test.is_initialized.
i log t and see that is_initialized's value is still initial.
Info :
If you want to test it yourself to answer my question of the why? and the how do i deal with it? but need some code for bluetoothle.isInitialized just use this:
var bluetoothle = {isInitialized:function(){setTimeout(function(){func({isInitialized:false});},20);}};
// to execute:
bluetoothle.isInitialized(/*callbackfunction*/);
I would like to thank you for reading this long question.
You're in a function. Inside a function (unless it's declared as Test.prototype.isInitialized), the scoping rules for 'this' are different. This is one of the gotchas that ES6 aims to eliminate. (If you added "use strict"; at the top of the function most browsers would tell you this.)
Declare var self = this in Test and use self inside your interior function and you should get the result you want. #squint has pretty much already said this.
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I'm new to this so i guess i'm missing something simple. The foor loop works fine but inside it i get an undefined variable
var categories_info = ["historia","excelencia","arte","social","instalaciones","padres","familia"];
for ( var i = 0; i < categories_info.length; i++) {
$("#showMe-"+categories_info[i]).click(function(){
$(".info."+categories_info.[i]).addClass("info-show");
console.log(".info."+categories_info[i]); //debug is undefinded
});
};
You need to create a closure like
var categories_info = ["historia", "excelencia", "arte", "social", "instalaciones", "padres", "familia"];
for (var i = 0; i < categories_info.length; i++) {
(function(i) {
$("#showMe-" + categories_info[i]).click(function() {
$(".info." + categories_info[i]).addClass("info-show");
console.log(".info." + categories_info[i]);
});
})(i);
};
This method is known as an IIFE
Basically, what was happening is the variable i was unavailable to the callback when the actual click happened.
However, by passing i in a self-executing anonymous function, you have created a closure which will preserve i and is accessible to the click handler.
Use a closure. Change:
$("#showMe-"+categories_info[i]).click(function(){
$(".info."+categories_info.[i]).addClass("info-show");
console.log(".info."+categories_info[i]); //debug is undefinded
});
To:
(function( i ) {
$("#showMe-"+categories_info[i]).click(function(){
$(".info."+categories_info.[i]).addClass("info-show");
console.log(".info."+categories_info[i]);
});
})( i );
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Javascript closure inside loops - simple practical example
I am using webservice to get the data in the form of JSON by using javascript and want to store that data in Sqlite Database. here i used for loop to store data one by one in Database by executeSql Query. But problem is function inside the for loop getting "i" value out of scope means showing undefined. I am trying to solve this problem by last 5 days. Any suggestion ?
Thanks
function GetGeoValues() {
$.get("http://example.in/projects/api.php?usn=user&pwd=****&var=something", function (Jdata) {
var geoid = new Array();
var geoname = new Array();
var i;
for (i = 0; i < Jdata.vact_geography.length; i++) {
geoid.push(Jdata.vact_geography[i].geo_id);
geoname.push(Jdata.vact_geography[i].geo_name);
db.transaction(function (transaction) {
alert(geoid[i]); // here i showing undefined
transaction.executeSql('INSERT INTO vact_geography VALUES(' + parseInt(geoid[i]) + ',"' + geoname[i] + '")');
});
}
});
}
I'm not sure, but this can happen, if function(transaction) executed in asynchronous mode. In this case variable i after for loop is finished must be equals to Jdata.vact_geography.length, and, as result geoid[i] equals to undefined. To workarround this try next:
function GetGeoValues() {
$.get("http://example.in/projects/api.php?usn=user&pwd=****&var=something",
function(Jdata) {
var geoid=new Array();
var geoname=new Array();
for(var i=0;i<Jdata.vact_geography.length;i++) {
geoid.push(Jdata.vact_geography[i].geo_id);
geoname.push(Jdata.vact_geography[i].geo_name);
}
db.transaction(function(transaction) {
for(var i=0;i<geoid.length;i++) {
alert(geoid[i]); // here i showing undefined
transaction.executeSql('INSERT INTO vact_geography VALUES('+parseInt(geoid[i])+',"'+geoname[i]+'")');
// All INSERT's executed in one transaction
}
});
}
);
}
Here inner function and outer function concept is considered. So the outer function have the var i. But in inner function i is not defined. Thats y its throwing error as "undefined"
Here is my dilemma.
I've got this section of code:
var list_of_numbers = new Array();
function AddToArray(func)
{
// Add to the *beginning* of the array
// essentially reversing the order
list_of_numbers.unshift(func);
}
function DisplayNumber(num)
{
document.write(num);
}
for(var i=0;i<5;++i)
{
AddToArray(function() { DisplayNumber(i); });
}
for(var i=0;i<5;++i)
{
list_of_numbers[i]();
}
What is supposed to happen is that 5 inline functions will be added to the array - each taking a copy of i. However this does not happen.
Expected output:
43210
Actual output:
01234
You have two separate issues, both related to scope.
var list_of_numbers = new Array();
function AddToArray(func)
{
// Add to the *beginning* of the array
// essentially reversing the order
list_of_numbers.unshift(func);
}
function DisplayNumber(num)
{
document.write(num);
}
for(var i=0;i<5;++i)
{
(function(i)
{
AddToArray(function(){ DisplayNumber(i); });
})(i);
}
for(var j=0;j<5;++j)
{
list_of_numbers[j]();
}
The anonymous function you're passing to AddToArray is bound to the variable i, not the current value. To address this, we create a new function, and pass in the current i.
JavaScript has function scope, so when you re-declare i in the second loop, you're still modifying the same variable. Thus, we rename it to j.
If only the first were an issue, you would get 55555, since all functions would use the same i, at that point 5. However, since you reuse i for the second index, i is set to the current loop index.