This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
I have many days that I can not run this script!
var b = [9,8,7,6,5,4,3,2,1];
var a = (function(){
var W = [];
for(var k in b){
W[W.length] = {
index : k,
fx : function(){
console.log(k);
}
}
}
return W;
})();
console.log(a);
for(var j = 0; a[j]; j++)a[j].fx();
Because it does not produce as OUTPUT numerical sequence 987654321?
Each function fx that you create references the variable var k. They don't save the current value of k, only a reference to k. This means that when you run the functions, after the for loop has finished, the value of k is now 8, and they all print that.
Once way to avoid this, and give each function its own variable/value, is to change var k to let k (available since ECMAScript 6). See let at MDN.
var b = [9,8,7,6,5,4,3,2,1];
var a = (function(){
var W = [];
for (let k in b) {
W[W.length] = {
index : k,
fx : function(){
console.log(k);
}
}
}
return W;
})();
for(var j = 0; a[j]; j++)
a[j].fx();
Related
This question already has answers here:
How to check if object property exists with a variable holding the property name?
(11 answers)
Closed 5 years ago.
I want to make an array so that it contains some identity name and for each of those names there is another array associated. My approach is like,
for (var i = 0; i < 10; i++) {
for (var x = 0; x < 5; x++) {
var data = someServiceCall(i, x);
var identityName = i + '-' + x;
myArray[identityName] = data;
}
}
after executing this i get something like,
[1-1: Array(8), 1-2: Array(10), 1-3: Array(10), 1-4: Array(10),.. etc]
the next time I call this function I need to check whether 1-1 exists and if yes I need to get the list related to 1-1. How can I do this..? if 1-1 is not in the myArray I will call some other function.
To check if the element having the 1-1 key exists just do:
if("1-1" in myArray)
Then to access the array associated with 1-1 use:
myArray["1-1"]
Try this. It inserts an object containing the identity name and data in each array element.
var myArray = [];
for (var i = 0; i < 10; i++) {
for (var x = 0; x < 5; x++) {
var data = someServiceCall(i, x);
var identityName = i + '-' + x;
var objectInArr = {
'identityName': identityName,
'data' : data
};
myArray.push(objectInArr);
};
};
try like this
myArray["1-1"] != undefined
Check if key exists in your array or not and act accordingly. Following is a working code snippet
var myArray = [];
for (var i = 0; i < 10; i++) {
for (var x = 0; x < 5; x++) {
var identityName = i + '-' + x;
myArray[identityName] = [1, 2];
}
}
var key = "0-0";
if(myArray[key])
console.log(myArray[key]);
you can check your array lenght and if the array is empty you will know that you need to call another action as you say. something like below might work for you
if (myArray.length === 0) {
//Call another function}
else {
//Somthing else}
This question already has answers here:
What is the difference between "let" and "var"?
(39 answers)
Closed 5 years ago.
Although i understand that let allows you to declare variables that are limited in scope to the block, I encountered a strange difference between let and var while using it with javascript closures. Here is my example:
With let:
function buildFunction() {
var arr = [];
for(var i = 0; i < 3; i++) {
let j = i; //Using let to assign j
arr.push(
function(){
console.log(j);
}
)
}
return arr;
}
var fs = buildFunction();
fs[0]();
fs[1]();
fs[2]();
The above code snippet outputs:
0
1
2
With var:
function buildFunction() {
var arr = [];
for(var i = 0; i < 3; i++) {
var j = i; //Using var to assign j
arr.push(
function(){
console.log(j);
}
)
}
return arr;
}
var fs = buildFunction();
fs[0]();
fs[1]();
fs[2]();
The above code snippet outputs the following:
2
2
2
My question is:
If U am using var inside a block and assigning it a value during execution, shouldn't it work exactly like let and store different copies of j in memory ?
Does javascript handle let and var differently within a closure ?
Any clarifications on this would be highly appreciated.
var scopes to the function; let scopes to a block of code.
In your example j is scoped to the function buildFunction() when you use var. This means your using the 'same' j in every function. When your for loop runs j is set to 0, then 1, then 2. When you then run the console logs your referencing the j that was set to 2, so you get 2 2 2.
When you use let, you scope j to that iteration of the for loop. This means every iteration has a 'different' j, and the console logs print what you expect them to print.
If you were using ES5 and needed to use var, you could replicate the let effect (have it print 0 1 2), by wrapping your original anonymous function with a self-executing function and passed j in as an argument. This would create a new scope for j in the self-executing function whose value is the value of j in the current iteration.
function buildFunction() {
var arr = [];
for(var i = 0; i < 3; i++) {
var j = i; //Using var to assign j
arr.push(
//self executing function
(function(j) { //j here is scoped to the self executing function and has the value of j when it was called in the loop. Any changes to j here will not affect the j scope outside this function, and any changes to j outside this function will not affect the j scoped inside this function.
//original function
return function() {
console.log(j);
}
})(j) //call with the value of j in this iteration
)
}
return arr;
}
var fs = buildFunction();
fs[0]();
fs[1]();
fs[2]();
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
I was trying to print first array element using recursive function but output is not as expected.
var modelArray = [1,2,3];
var refurbArray = [a,b];
for (var z = 0; z < modelArray.length; z++) {
for (var y = 0; y < refurbArray.length; y++) {
var check = modelArray[z];
var recursive(refurbArray[y], function() {
consol.log(check);
});
}
}
Expected output:
1
1
2
2
3
3
Obtained output:
3
3
3
3
3
3
The problem you are having is that recursive have deferred the call to your call back function (likely due to some async functionality inside the recursive), and the value of check has changed when the callback function is finally executed.
You need to bind the check in a closure, for which there are several options and coding style on how to do, but example like
for (var z = 0; z < modelArray.length; z++) {
for (var y = 0; y < refurbArray.length; y++) {
(function() {
var check = modelArray[z];
recursive(refurbArray[y], function() {
consol.log(check);
});
})();
}
}
Try with something like:
var modelArray = [1,2,3];
var refurbArray = ['a','b'];
function recursive(val, cb){
cb();
}
for (var z = 0; z < modelArray.length; z++) {
for (var y = 0; y < refurbArray.length; y++) {
var check = modelArray[z];
recursive(refurbArray[y], function() {
console.log(check);
});
}
}
You print the check variable in the refurbCallback and that remains set to the last value of var check = modelArray[z];
This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 7 years ago.
I have code that looks like this:
var a = [];
for(var i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
}
}
Unfortunately, it seems that i is being passed by reference, so all the functions in a output 10. How do I make it so that each function outputs the value that i had when it was created? I.e. a[0]() gives 0, a[1]() gives 1, etc.
EDIT: to clarify, I do not want a to store the values 0-9. I want a to store functions that return the values 0-9.
You need to invoke a function (to create a closure that captures your value) which returns a function (the one you want to end up with). Something like this:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = (function(value) {
return function() {
console.log(value);
}
})(i);
}
var a = [];
for(var i = 0; i < 10; i++) {
a[i] = (function(j) {
return function () {
console.log(j);
}
})(i);
}
A better performing version -
function makeFunction(i) {
return function () {
console.log(i);
}
}
var a = [];
for(var i = 0; i < 10; i++) {
a[i] = makeFunction(i);
}
JSFiddle Demo.
I have ~16.000 items (one item is an array, has 6 values). All items have 5 "attributes", they're numbers. I need to store them, and when I know the attributes, return the item, as fast as possible. I tried 2 kind of methods:
Objects in objects. If a = attribute1, b = attribute2 ... to e, then I can get the item the user's looking for by data1[a][b][c][d][e]. The full data stored in this format: http://jpst.it/z12-
One object, but it has 16k arrays, the object's properties are the given item's attributes. Then myItem = data2[""+a+b+c+d+e]. http://jpst.it/z13p
I ran some tests to see which method is the faster:
var test,
a = 30175,
b = 5,
c = 1,
d = 1,
e = 60,
abcde = 301755360;
console.time("test1");
for (var i = 0; i < 9999999; i++)
test = data1[a][b][c][d][e];
console.timeEnd("test1");
console.time("test2");
for (var i = 0; i < 9999999; i++)
test = data2[abcde];
console.timeEnd("test2");
Results on my PC:
test1 test2
Firefox: 1482.00ms 1341.00ms
Chrome: 665.00ms 424.00ms
Explorer: 12555.17ms 4945,50ms
The second method is always faster. But why? I ran another test to know how many times the JS have to check if the given object's key equals to the needed key:
var x = 0;
function fn(obj, myKey) {
for (var key in obj) {
x++;
if (key == myKey)
return obj[key];
}
}
Method 1: fn(fn(fn(fn(fn(data1, a), b), c), d), e); => x is 352.
Method 2: fn(data2, abcde); => x is 3154.
However, method 2 isn't 10x slower, it's even faster.
This might give you an idea of what's going on. 2nd getter is called 9 times, first getter is called 45 times. Each time it first has to access 30186, then 6, then ... 5 calls for each iteration to get the value.
var x = 0;
var y = 0;
var data1 = {"30186":{"6":{"1":{"1":{"0":[4,1430745862,"3 - 5 ref","4 ref","4 ref",1]}}}}};
var data2 = {"3018663":[4,1430745862,"3 - 5 ref","4 ref","4 ref",1]};
Object.prototype.get = function(i) { x++; console.log(i); return this[i]; }
Object.prototype.get2 = function(i) { y++; return this[i]; }
for (var i = 0; i < 9; i++)
test = data1.get(30186).get(6).get(1).get(1).get(0);
for (var i = 0; i < 9; i++)
test = data2.get2(3018663);
console.log(x, y);