I've created a simple forEach function and I'm trying to understand why, when I run it with myArray, it doesn't mutate the array even though I run element*2.
function forEach(array, callback) {
for (var i = 0; i < array.length; i++) {
callback(array[i],i,array)
};
}
var myArray = [1,2,3]
forEach(myArray,function(element){element*2})
console.log(myArray)///[1,2,3]
You have to modify the array in the for loop, like this:
function forEach(array, callback) {
for (var i = 0; i < array.length; i++) {
array[i] = callback(array[i],i,array)
};
}
var myArray = [1,2,3]
forEach(myArray,function(element){return element*2})
console.log(myArray)
As we were discussing in the comments, the best way would be to implement something like the map function: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/map
function map(array, callback) {
var out = [];
for (var i = 0; i < array.length; i++) {
out.push(callback(array[i],i,array))
};
return out;
}
var myArray = [1,2,3]
var myOtherArray = map(myArray,function(element){return element*2})
console.log(myArray)
console.log(myOtherArray)
This way myArray is not touched, you create a new one. This is usually the best option, but sometimes you may want to modify it in place, because it is huge or for some other (good?) reason. In that case you can use the first option.
You should assign new array element value, because primitive types (like numbers in your case) are immutable, so element * 2 does not modify element.
To do the job, you should not touch you current forEach implementation, because forEach is not supposed to return values from callback (this is not map). In this case you should do something like this:
function forEach(array, callback) {
for (var i = 0; i < array.length; i++) {
callback(array[i], i, array);
}
}
var myArray = [1,2,3];
forEach(myArray, function(element, i, arr) {
arr[i] = element * 2;
});
document.write(JSON.stringify( myArray ));
This should work, explicitly assigning the variable.
function forEach(array, callback) {
for (var i = 0; i < array.length; i++) {
array[i] = callback(array[i])
};
}
var myArray = [1,2,3]
forEach(myArray,function(element){return element*2})
console.log(myArray)///[1,2,3]
Yep, bad answer. This [snippet] would do it though.
Anyway, in modern browsers we have Array.forEach to availability
function foreach(array, callback) {
for (var i = 0; i < array.length; i++) {
array[i] = callback(array[i]);
// ^ assign the new value (from the callback function)
};
}
var myArray = [1,2,3]
foreach( myArray, function (element){ return element * 2 } );
// ^ return the new value
document.querySelector('#result').textContent = myArray;
<pre id="result"></pre>
Related
I want to access array variable outside the loop. but its returning null. below is sample code.
var result = [];
for (var i=0; i < 10; i++) {
result.push[i];
}
The syntex of push method is push() not push[].
var result = [];
for (var i=0; i < 10; i++) {
result.push(i);
}
console.log(result);
For more info about push() look How to append something to an array?
push is a method implemented on array. The basic syntax of invoking or calling a function is to specify parenthesis () after the function name.
Array.prototype.push()
The push() method adds one or more elements to the end of an array and returns the new length of the array.
var result = [];
for (var i=0; i < 10; i++) {
result.push(i);
}
console.log(result);
Please use the below code:
var result = [];
for (var i=0; i < 10; i++) {
result.push(i);
}
You can do that like this also.
var result = [];
for (var i=0; i < 10; i++) {
result[i]=i;
}
If you want to use push then use like this result.push(i)
When i loop through the array using the splice method, the page just freezes. It looks like i caused an infinite loop. lib.randomInt() works, so that is not the problem.
function() {
return function(string) {
var arr = string.split("")
arr.sort();
for(var i = 0; arr.length;i++){
arr.splice((i+1),0,lib.randomInt(9));
}
var pseudocryptarr = arr.join("");
}
})()("example");
This is from a different file that is placed above the main file in html
var lib = {
factorial: function(num){
function _factorial(num){
if(num === 1){
return 1;
} else {
return num*_factorial(num-1);
}
}
console.log(num+"! = " + _factorial(num));
},
randomInt: function(int,offset){
if(offset == undefined || null || NaN){
offset = 0;
}
return Math.floor(Math.random()*int)+offset;
},
display: function(m, fn){
fn(m);
}
};
You've got to loop in reverse when modifying the array itself to avoid corrupting the loop like this...
for (var i=arr.length-1; i>=0; i--){}
I guess that you wanted to insert a random value after every array element, so that the string "example" would become something like "e5x9a2m4p7l1e3"
There are two issues:
Your for loop has no end condition that will become false. You need to state i < arr.length instead of just arr.length which is always truthy for non-empty arrays.
You add array elements in every iteration, but then also visit them in the next iteration, and from there on you will only be visiting the new inserted values and never get to the next original element that keeps being 1 index away from i. You need to increment i once more. For that you can use ++i instead if i+1 as the splice argument.
So your loop should be:
for(var i = 0; i < arr.length; i++) {
arr.splice(++i,0,lib.randomInt(9));
}
const lib = { randomInt: n => Math.floor(Math.random()*n) };
(function() {
return function(string) {
var arr = string.split("")
arr.sort();
for(var i = 0; i < arr.length; i++) {
arr.splice(++i,0,lib.randomInt(9));
}
var pseudocryptarr = arr.join("");
console.log(pseudocryptarr);
}
})()("example");
Or to save an addition:
for(var i = 1; i <= arr.length; i+=2) {
arr.splice(i,0,lib.randomInt(9));
}
const lib = { randomInt: n => Math.floor(Math.random()*n) };
(function() {
return function(string) {
var arr = string.split("")
arr.sort();
for(var i = 1; i <= arr.length; i+=2) {
arr.splice(i,0,lib.randomInt(9));
}
var pseudocryptarr = arr.join("");
console.log(pseudocryptarr);
}
})()("example");
I fixed it. I wanted after each character for there to be a number. Using the pre-looped array length and doubling it while iterating twice, means that the splice adds the number after the new number element and then the character.
Edit: My typo was the problem. I didnt even have to use len, just iterate by 2.
for(var i = 0;i < arr.length;i+=2){
arr.splice((i+1),0,lib.randomInt(9));
}
(function() {
return function(string) {
var arr = string.split("")
arr.sort();
var len = arr.length
for(var i = 0;i < len*2;i+=2){
arr.splice((i+1),0,lib.randomInt(9));
}
var pseudocryptarr = arr.join("");
console.log(pseudocryptarr);
}
})()("example");
Edit: user4723924 method is better:
(function() {
return function(string) {
var arr = string.split("")
arr.sort();
for(var i = arr.length;i >= 0;i--){
arr.splice((i+1),0,lib.randomInt(9));
}
var pseudocryptarr = arr.join("");
console.log(pseudocryptarr);
}
})()("example");
I am confused about how to iterate on multiple values.
for example : values.categories[0].num[0].entry[0].label;
Do I need to write three for loops in order to iterate through categories, num and entry.
Because categories[0] will always identify the 1st position, but am looking for generic categories[i].
Can you please help me out whether to write three for loops or better option is there to achieve.?
This is what I have tried:
var result = [];
for (var i = 0; i < categories.length; i++) {
var abc = categories[i].num;
for (var j = 0; j < abc.length; j++){
var def = num[i].entry;
}
for(var k = 0; k < def.length; k++){
var ghi = entry[i].label;
result.push(ghi)
console.log(result);
}
}
you can use the each function of jquery.
$.each(categories, function(ci, num) {
// This set the index of the array in ci and the value in num = categories[ci]
$.each(num, function(ni, entry) {
// etc ...
});
});
if you want it to stop the iteration you can return false inside the callback function.
Is there a shortcut to accessing elements of an array using an array of indices rather than going one index at a time?
Example (this doesn't work):
var array = ["One", "Two", "Three", "Four"];
var indices = [1, 3];
var result = array[indices];
where result would be ["Two", "Four"].
You can make one and have it available to all Arrays if you've no qualms about extending native prototypes in your environment.
Array.prototype.atIndices = function(ind) {
var result = [];
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] in this)
result.push(this[arguments[i]])
}
return result;
}
var result = array.atIndices(1,3);
You could also have it check to see if an Array was passed, or a mix of indices and Arrays.
Array.prototype.atIndices = function(ind) {
var result = [];
for (var i = 0; i < arguments.length; i++) {
if (Array.isArray(arguments[i]))
result.push.apply(result, this.atIndices.apply(this, arguments[i]))
else if (arguments[i] in this)
result.push(this[arguments[i]])
}
return result;
}
This will actually flatten out all Arrays, so they could be as deeply nested as you want.
var result = array.atIndices(1, [3, [5]]);
Now there is:
function pluck(arr, indices) {
var result = [],
i = 0,
len = indices.length;
for (; i < len; i++) {
result.push(arr[indices[i]]);
}
return result;
}
As an alternative to rolling your own, if you have access to Lo-Dash (which you should totally use because it is awesome) its at function does exactly what you want.
Your usage would be:
var result = _.at(array, indices);
See: http://lodash.com/docs#at
Given this function call:
var funcs = obj.getClosures([2, 4, 6, 8], function(x) {
return x*x;
});
I have the following function:
getClosures : function(arr, fn) {
var funcs = [];
var array = arr;
var i = 0;
var l = array.length;
(function(i, array) {
for (; i < l; i++) {
funcs[i] = function(i, array) {
return fn(array[i]);
};
}
}(i, array));
return funcs;
},
I'd like to be able to loop through the returned array and get the square root values of each item in the array exactly like this:
for (var i = 0; i < arr.length; i++) {
funcs[i]();
}
results each time through loop : 4, 16, 36, 64
Shouldn't my funcs array have a function reference in each index that can be readily invoked with the relevant argument values? Where did I go wrong?
There multiple "issues":
The IIFE (function(i, array) { ... }(i, array)); has no benefit at all here. If you remove it the code will have the exact same behavior. If you want to capture the current value of i and array, you would have to move it inside the for loop.
Your function definition is incorrect.
funcs[i] = function(i, array) {
return fn(array[i]);
};
Inside the function, array[i] will refer to the arguments you pass to the function. If you don't pass any, they will be undefined and the code will throw an error. That is, with that definition, you would have to execute the functions like so:
for (var i = 0; i < arr.length; i++) {
funcs[i](i, array);
}
which kind of defeats the purpose of generating the functions in the first place.
If you want to create a closure which has access to i and array of the scope where the function was defined in, don't define parameters with the same name.
Possible solution:
for (var i = 0, l = array.length; i < l; i++) {
(function(i) {
funcs[i] = function() {
return fn(array[i]);
};
}(i));
}
Or simpler, if your code runs in environments which support .map:
getClosures: function(arr, fn) {
return arr.map(function(v) {
return function() {
fn(v);
};
});
},
Related questions:
JavaScript closure inside loops – simple practical example
How do JavaScript closures work?
Read about Function.prototype.bind:
var obj = {
getClosures : function(arr, fn) {
var funcs = [];
var array = arr;
var i = 0;
var l = array.length;
(function(i, array) {
for (; i < l; i++) {
funcs[i] = function(i, array) {
return fn(array[i]);
}.bind(this,i,array);
}
}(i, array));
return funcs;
}
}
var funcs = obj.getClosures([2, 4, 6, 8], function(x) {
return x*x;
});
for (var i = 0; i < funcs.length; i++) {
console.log(funcs[i]());
}
Outputs:
4
16
36
64
It works since javascript 1.8.5 (firefox 4). I have no idea for other browsers but there is implementation for older versions (should work on older browsers as well)