I have a piece of JavaScript code that I want to create a list of functions. All the functions will be put in a dictionary d. d["a"] will give me the function function() {console.log("a")} and d["b"] will give me the function function() {console.log("b")} etc. This is my code:
var a = "abcdefghijklmnopqrstuvwxyz1234567890".split("");
var d = {};
for(var l = a.length, i = 0; i < l; i++)
{
d[a[i]] = function(){console.log(a[i])};
}
However, when I run the above code, d["a"] and d["b"] will be the same, they all point to function(){console.log(a[i])}. How to get what I want?
Thanks.
You need to give each instance of the function its own variable:
for(var l = a.length, i = 0; i < l; i++)
{
(function (x) {
d[a[x]] = function(){console.log(a[x])};
})(i)
}
They don't point to the same instance of function(){console.log(a[i])}, instead, you've created a bunch of functions that all use the same reference to i. The value that i points at changes as the for loop executes.
The other answers provided will work, but it involves generating twice as many functions as you need.
function makeLogFunction(whatToLog) {
return function() {
console.log(whatToLog);
}
}
var a = "abcdefghijklmnopqrstuvwxyz1234567890";
var d = {};
for(var l = a.length, i = 0; i < l; i++) {
d[a[i]] = makeLogFunction(a[i]);
}
Here, I have a makeLogFunction that will return a new function that always prints whatToLog. The other answers will generate a new "version" of the makeLogFunction every time the loop executes. For very large sets of data, this is a waste of time and memory.
This approach has added advantages of clarity and reusability. If there's a significant amount of logic happening in your loop, encapsulating it in a named function allows future reviewers to get a sense of what's going on by the name you give to the function. You can also reuse the function in other parts of your application.
Related
I am new to programming and sorry if a question is dumb.
I am using several functions with variables i, j for looping like - for( j = 0; j < pol.length; j++) ...
Now my lack of knowledge is - I think that declaring "var i = 0..." in every function will creates a memory problem because these functions are used many times and it will declare "i" or "j" each time. So what I do now is I declare var i,j = 0; once outside the functions as a global and then just use them in functions without "var". But I have a feeling - this is terribly wrong.
Another variables that I declare as global "var" are the ones I use later in some functions. For example - var pol_owner = ""; So the code will play with these variables later and change their values. And now I have something like this at the start of my document:
var thePol = 0;
var nondrag = 0;
var intGl = 0;
var intMn = 0;
var oldGl = 0;
var oldMn = 0;
var money = 0;
var gifts = 0;
var g_spent = 0;
var the_mess = "";
var j = 0;
var x = 0;
var y = 0;
var i = 0;
And later my functions just use these variables without "var".
I know though the code runs well still I am doing it wrong. Can you give me any advice of how to properly do it. I was looking for some information about it but still I am not sure what is the proper way of doing it.
From the start I was doing my code as: for( var j = 0; j < pol.length; j++) not declaring "j" outside the function, but later I thought that every-time this function run it will declare this var again and again and will not it be more effective to declare it once from the start and later use it without "var". The only problem I see is - creating a global variable that I can accidentally use wrong in some part of the code. But I am kind of controlling this.
So the question basically is - is declaring "var i=0" in every loop part of the function creates any memory problem and should I declare this var once outside the function and use it later without declaration to avoid this problem?
Thank you in advance.
I am learning javascript and came across a topic which mentions that the variables declared inside a function is available anywhere inside the function and javascript puts the variable definition at the top like in the below example:
var functionScope=function(){
for (var i=0; i< 10; i++){//code inside this loop}
return i;
}
console.log(functionScope()); //prints 10
The javascript actually turns the above function to the below:
var functionScope=function(){
var i;
for ( i=0; i< 10; i++){//code inside the for loop}
return i;
}
console.log(functionScope()); //prints 10
Since javascript is interpreted language, it executes line by line. How will it know that it should pull the variable to the top of the function after it has tried accessing the variable. When it tries to access the variable it should tell as undefined right?
Also if I go by the theory that the variables will be placed at the top of the function and can be accessed anywhere then the below code should print 10, but why the below code prints undefined?
var functionScope=function(){
console.log('The value os i is '+i);
var i = 20;
}
console.log(functionScope());
Could someone explain where my understanding is wrong?
One more doubt: Typically in Java, if I had to print the value of i outside the for loop, i would get an error, but in javascript does the variable still accessible outside outside the for loop as in case of fist example where the variable is defined inline inside the for loop. Am i missing something here?
var functionScope=function(){
for (var i=0; i< 10; i++);
return i
}
console.log(functionScope()); //prints 10
This is only a bad indentation. Because of the ; at the end of for, it doesn't includes the return i statement into the loop.
There is the well indented one to help you understand what really happens:
var functionScope=function() {
for (var i=0; i< 10; i++)
/* do nothing */;
return i
}
With var, you tell the JS that the variable is not global, and it'll be aviable only inside the function.
With =, you can set the variable's value.
var i; for (i = 0; ... and for (var i = 0; ... is the same.
In the third example, you don't have i inside the function. In this case, the JS'll try to find it as a global variable, outside the function. If you've set window.i = 1, it'll print The value os i is 1, otherwise it'll generate an error, because i is not defined nowhere.
var i = 0;
var fn = function() {
i = 1; //window.i = 1;
};
console.log(i); //prints 1
var i = 0;
var fn = function() {
var i = 1; //fn.i = 1;
}
console.log(i); //prints 0
var fn = function() {
var i = 1; //fn.i = 1;
}
console.log(i); //ReferenceError: i is not defined
var i;
var fn = function() {
var i = 1; //fn.i = 1;
}
console.log(i) //prints undefined
As Sebastien C. has already told you, your example code dosn't do what you want it to do. for (var i=0; i< 10; i++); means for (var i=0; i< 10; i++) {/*do nothing*/}. If you remove the ;, you'll notece your function will return 0, because the return keyword stops the function, and it return the value, no other operations will be executed, your loop will run only once.
Also, you should use ++i.
Yes Javascript is interpreted and whenever is finds a var declared/undeclared, it declares it and then performs the operations or in technical terms it does var hoisting. So now the variable is declared, but is undefined.
So any operation done on it (other than assignment) will result in its value being undefined only. eg;
{
x++ ;
var x = 10 ;
console.log(x);
}
will print 10. So you can think of it as
{
var x = undefined; \\variable hoisted at beginning of block
x++ ;
x = 10 ;
console.log( x ); \\ x = 10
}
Getting the negative value when i perform the onclick function in javascript
function sun()
{
var d,i;
var t = document.getElementById("table");
var rows = t.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
console.log("inside............." + i);
rows[i].onclick = function() {
d = (this.rowIndex);
console.log(d);
};
}
}
Though I'm not sure it's what's causing the exact issue you're noticing, you've encountered a pretty common JavaScript pitfall here by using a closure (anonymous function) inside of a loop. JavaScript, like many other languages that support functional programming, has the convenient property that functions can "close scope" around any variables visible to them at the time of their creation. So, as you've done there, you can use the value of d (or i) inside your function so long as it can see them when your function is declared.
Something funny happens inside a loop, though: every function you create within the loop shares the same scope, meaning they all share the exact same copies of d and i. As a result, when you click on any of your rows, the values of d and i used will be their values at the end of the loop, not the particular iteration you're targeting.
This is ordinarily fixed using something known as the "generator pattern," where you create a separate function that returns new functions closed over your desired scope. For example, in your code, you might do something like
function generateClickHandler(i, d) {
return function() {
d = (this.rowIndex);
console.log(d);
};
}
function sun()
{
var d,i;
var t = document.getElementById("table");
var rows = t.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
console.log("inside............." + i);
rows[i].onclick = generateClickHandler(i, d);
}
}
The new function generateClickHandler returns a function itself, but the important thing to notice here is that the returned function closes over the local arguments i and d, not the shared i and d values used in the loop — their values get copied when you call generateClickHandler. In this way, your code won't be subject to strange closure effects.
I am trying to make a cell in a table tell me its number when I click it.
for(var j = 0; j < 8; j++){
var cell = row.insertCell(j);
cell.name = j;
cell.onclick=function(){alert(cell.name)};
}
This however, prints the number 8 for every cell. How do I save the value of j in cell.name, instead of just having it point to the variable j?
Thanks.
IMPORTANT: All JavaScript developers should know this. It will cause all kinds of weird bugs that is very hard to find.
It is a common mistake of people who are new to JavaScript. I've made the same mistake before.
A function inside a loop is NOT created for every iteration. It is the same one function object with the same closure scope. Thus, your cells will have the exact same onclick callback.
My advice here is NEVER EVER create a function inside of loop. Instead, create and call a function that returns a callback function and assign it to onclick.
for (var j = 0; j < 8; j++) {
var cell = row.insertCell(j);
cell.name = j;
cell.onclick = createOnClick(cell);
}
function createOnClick(cell) {
return function () {
// do whatever you want to do with cell
};
}
Hello I'm working on a problem that requires me to change an set array of numbers into an array that returns the original numbers as a function. So we get a return of a2 instead of a[2].
I dont want the answer I just need a hint. I know i can loop through the array and use .pop() to get the last value of the array, but then I dont know how to convert it to a function from there. any hints?
var numToFun = [1, 2, 3];
var numToFunLength = numToFun.length;
for (var i = 0; i < numToFunLength; i++) {
(function(num){
numToFun.unshift(function() {
return num;
});
}(numToFun.pop()))
}
DEMO
basically it pops out a number from the last, builds a function with that number returned, and put back into the first of the array. after one full cycle, all of them are functions.
here's the catch: how this works, it's up to you to research
why the loop does not look like the straightforward pop-unshift:
for (var i = 0; i < numToFunLength; i++) {
numToFun.unshift(function() { //put into first a function
return numToFun.pop() //that returns a number
});
}
and why i did this: (HINT: performance)
var numToFunLength = numToFun.length;
There's three important steps here:
Extract the number value from the array. Within a loop with an iterator of i, it might look like this:
var num = numArray[i];
This is important, because i will not retain its value that it had when you created the new function - it'll end up with the last value it had, once the for loop is finished. The function itself might look like this:
function() { return num; }
There's no reference to i any more, which is important - to understand better, read about closures. The final step would be to add the new function to the array of functions that you want.
...and you're done!
EDIT: See other's answers for good explanations of how to do this right, I will fix mine also though
As others have pointed out, one of the tricky things in javascript that many struggle with (myself included, obviously) is that scoping variables in javascript is dissimilar to many other languages; scopes are almost purely defined by functions, not the {} blocks of, for example, a for loop, as java/C would be.
So, below you can see (and in other answers here) a scoping function can aid with such a problem.
var numArray = [12, 33, 55];
var funcArray = [];
var numArrLength = numArray.length; // Don't do this in for loop to avoid the check multiple times
for(var j=0; j < numArrLength; j++) {
var scopeMe = function() {
var numToReturn = numArray[j];
console.log('now loading... ' + numToReturn);
var newFunc = function() {
return numToReturn;
};
return newFunc;
}();
funcArray.push(scopeMe);
};
console.log('now me');
console.log(funcArray);
console.log(funcArray[0]());
console.log(funcArray[1]());
console.log(funcArray[2]());
console.log(funcArray[1]()); // To ensure it's repeatable
EDIT my old bad answer below
What you'll want to do is something like
var funcArray = [];
for(...) {
var newFunc = function() {
return numArray.pop();
}
funcArray.push(newFunc);
}
The key here is that functions in javascript can be named variables, and passed around as such :)