JavaScript for loop Index becomes arrayIndex - javascript

I have the following JavaScript code fragment
var ip = new Array();
// This array filled with values and passed to function
function calculateTime(ip) {
for (i in ip) {
window.alert(i);
if (!i in myArray) {
myArray[i] = 0;
} else {
myArray[i] += 1;
}
}
}
I expect i to be an index (0, 1, 2 ...) but sometimes window.alert prints "arrayIndex" and because of that my code doesn't work correctly. Can someone explain me the reason? I am new in JavaScript.

for in will loop over all the enumerable properties of an object.
None of the properties that come with an array are enumerable in modern browsers, but any that are added (such as the normal array indexes or any custom named properties) will be.
Somewhere you have some code that is adding an arrayIndex property to your array and it is coming up when you loop over it.
var myArray = [];
myArray[0] = 1;
myArray[1] = 1;
myArray[2] = 1;
myArray.arrayIndex = 1;
for (prop in myArray) {
console.log(prop);
}
If you only want to get numerical indexes, then use a standard for loop.
for (var i = 0 ; i < myArray.length ; i++) {
console.log(i);
}

For arrays, you should use a numeric variable rather than in:
for(var i = 0; i < ip.length; i++)
in is to iterate over the keys of an Object, but even there you have to take much care to filter out inherited properties.
Now, since arrays are objects too in JavaScript, you can assign them object properties:
ip["arrayIndex"] = 'some value';
Then "arrayIndex" will show up in a for...in iteration, whereas in a "normal" for loop, it won't.

Use either
for(var i=0; i<ip.length; i++){
//your code
}
or
ip.forEach(function(val,i){
// your code
});
The for(var x in y) loop works best for Object rather than Array. When you use it on arrays it will loop through all properties including named ones like length not just numerical indices.

Related

Why on earth is jack showing up in the sequence of alert boxes?

Object.prototype.jack = {};
var a = [1,2,3];
for(var number in a){
alert(number);
}
Could anyone tell me why the word "jack" jumped out of the alert box?
Thank you very much!
Simple - arrays are objects in javascript so by adding:
Object.prototype.jack={};
You've added an enumerable property 'jack' to all objects (and by that to all arrays).
once creating your array "a" and looping through all of its properties
for(var number in a)
You are sure to get a 'jack' alert. To avoid it showing up you can use .hasOwnProperty() to make sure all alerted properties are not inherited. or use a regular
for(var i=0; i < a.length; i++)
loop.
The for..in loop iterates over properties. It's only recommended (by Mozilla and other authorities) to be used on Objects, but not Arrays. If you insist, this is the correct way to iterate over an object and it will work for an array (most of the time).
for (var number in a) {
if (Object.prototype.hasOwnProperty.call(a, number)) {
alert(a[number]); // shows 1 then 2 then 3
}
}
To do it the generally accepted way,
for (var i=0; i<a.length; i++) {
alert(a[i]); // same as above
}
My personal preference is:
for (var val, i=0; val = a[i]; i++) {
alert(val); // same as above
}
Because you're not checking if jack is a property inherited from prototype or not. Try this instead:
Object.prototype.jack={};
var a = [1,2,3];
for (var number in a) {
if (a.hasOwnProperty(number)) {
alert(number);
}
}

Mysterious 'function' being attached to array

I have the following code:
// button sets
var sets = ['.diamond-colour','.diamond-cut','.diamond-clarity','.diamond-certificate'];
// for each set
for (set in sets){
console.log('Set: '+set);
console.log(sets[set]);
}
The console log shows:
Set: 0
.diamond-colour
Set: 1
.diamond-cut
Set: 2
.diamond-clarity
Set: 3
.diamond-certificate
Set: findIndex
function (value){
var ctr = "";
for (var i=0; i < this.length; i++) {
if (this[i] == value) {
return i;
}
}
return ctr;
}
It appears to be a new array element with the key of findIndex and a value being that function.
Would anyone have any idea what this is and why it's appearing?
You should use a traditional for loop to iterate over an array, otherwise you may pick up properties (in this case a new function) added by yours or 3rd-party code.
for(var i = 0; i < sets.length; i++) {
As others have mentioned, caching the length provides optimal performance:
for(var i = 0, len=sets.length; i < len; i++) {
This is because the in operator with for loops in Javascript loops over the properties of the object, not just the objects in the "Array". I say "Array" because Javascript arrays are really just objects with numeric properties created for each entry in the array (and some additional methods and properties like .length).
As Dennis mentioned, you'll want to use a traditional for loop to loop over just the objects in the array.
Also note that an easy optimisation for such for loops is to initialise the length value once at the start of the loop, rather than evaluating array.length each time:
for (var i = 0, len = sets.length; i < len; i++) {
// ...
}

Syntax for iterating the comparison of one array to many other systematically named arrays

I have a question about proper syntax in iterative functions. I want to compare one master array to a large set (180+) of other arrays. The large set of arrays to be compared are systematically named (scorespec1, scorespec2, scorespec3...). Each comparison will be made not one-to-one but through an algorithm and then have the results stored in another set of arrays that are also systematically named for later query. I not worried about getting the algorithm right just yet. I'm just not sure of the proper syntax to iterate through my arrays. For instance, this is but one of the syntax structures I have tried but failed to get working:
for (i=01;i=186;i++){
if (scorespec+(i)[04]=unknownspec[16]){
resultarray+(i)[01]=True;
else
resultarray+(i)[01]=False;}}
My main problem here is I don't know how to structure the syntax to include the counter variable in my for-loop in the variable name. I've tried a variety of different syntaxes in addition to what I show above and it just doesn't seem to work right. What syntax should I be using?
There are three parts to the for statement:
for ([initialExpression]; [condition]; [incrementExpression]) {
// The statement (i.e. what will happen on each iteration)
}
To iterate through an array, we need the length of the array and a counter which will move towards that length as we iterate. This is the usual pattern:
var myArray = ['foo', 'bar', 'far']; //...
for (var i = 0; i < myArray.length; i++) {
myArray[i]; // <- this is the current array item
}
It's sensible to cache the array's length like so:
for (var i = 0, l = myArray.length; i < l; i++) {
myArray[i]; // <- this is the current array item
}
Also, FYI, your booleans, true and false, should not be capitalised.
If you had declared your array in global scope you could access them using the window object:
var scorespec1 = "123";
var scorespec2 = "456";
for ( var i = 1; i < 3; i++ ){
alert(window['scorespec' + i]);
}
Or you could use the slow and evil eval:
var scorespec1 = "123";
var scorespec2 = "456";
for ( var i = 1; i < 3; i++ ){
var scorespec;
eval("scorespec = scorespec" + i);
alert(scorespec);
}

Javascript: Iterating over array with non-consecutive keys

I need to iterate over an array for which the keys are non-consecutive:
var messages = new Array();
messages[0] = "This is the first message";
messages[3] = "This is another message";
Obviously using the index of a for loop will not work as it depends on the keys being sequential:
for (var i=0 ; i<messages.length ; i++) {
alert(messages[i]); // Will only alert the first message, as i is never equal to 3
}
What is the canonical way of dealing with this, seeing as the for-each syntax is not intended for iterating over values in an array in javascript? Thanks.
The idiomatic way would be to use an object, not an array. Just be sure to check hasOwnProperty to make sure you don't pick up stray things which may have been added to the prototype.
var messages = { };
messages[0] = "This is the first message";
messages[3] = "This is another message";
for (var i in messages) {
if (messages.hasOwnProperty(i))
alert(messages[i]);
}
Or, the more modern way would be to use Object.keys
Object.keys(messages).forEach(prop => {
alert(messages[prop]);
});
Be sure to transpile that code with Babel if you plan on running it in older browsers like IE.
for(var i in messages)
{
console.log(messages[i]);
}
You could ignore the undefined properties...
for (var i=0 ; i<messages.length ; i++) {
if(messages[i] !== undefined)
alert(messages[i]);
}
Or use forEach, which will ignore undefined undeclared properties...
messages.forEach(function(v,i) {
alert(v);
});
Simple! if the array has regular gaps between the indices do this:
for (var i = 0 ; i < messages.length; i += gap) {
alert(messages[i]); // Will only alert the messages at the regular interval/gap
}
You can use each() jQuery method to do this.
$.each(messages, function(index, val){
alert(val);
});
From jQuery docs
each()
A generic iterator function, which can be used to seamlessly iterate
over both objects and arrays. Arrays and array-like objects with a
length property (such as a function's arguments object) are iterated
by numeric index, from 0 to length-1. Other objects are iterated via
their named properties.
When you create an array and give it values at 0 and 3, undefined values are created at 1 and 2. try this:
$.each(messages, function(i,val) {
if (val) {
alert(val);
}
});
For a use case such with the assumptions:
array.length >== 1
(i.e: an array with meaningful data in it already)
Where you are interested in the data from array[1], array[15], array[45] etc
You can do something similar to:
var array = ["you","will","become","strong","with","the","codes","padawan"];
var values = [1,5,7];
for (var i = 0; i < values.length; i++){
var cypher = values[i];
console.log(array[cypher]);
}
//will, the, padawan
Or perhaps something more meaningful such as:
for (var i = 0; i < values.length; i++){
var cypher = values[i];
aService.aFn.(array[cypher],cb);
}
//calls aService.aFn separately for each value array[1] , array[5] , array[7] passed as args

Loop through associative array in reverse

I'm using a javascript associative array (arr) and am using this method to loop through it.
for(var i in arr) {
var value = arr[i];
alert(i =") "+ value);
}
The problem is that the order of the items is important to me, and it needs to loop through from last to first, rather than first to last as it currently does.
Is there a way to do this?
Four things:
JavaScript has arrays (integer-indexed [see comments below]) and objects (string-indexed). What you would call an associative array in another language is called an object in JS.
You shouldn't use for in to loop through a JS array.
If you're looping through an object, use: hasOwnProperty.
JavaScript doesn't guarantee the order of keys in an object. If you care about order, use an array instead.
If you're using a normal array, do this:
for (var i = arr.length - 1; i >= 0; i--) {
//do something with arr[i]
}
Warning: this answer is ancient.
If you're here for a quick fix, kindly refer to the much better answer below.
Original answer retained, because reasons. See comments.
Using a temporary array holding the keys in reverse order:
var keys = new Array();
for (var k in arr) {
keys.unshift(k);
}
for (var c = keys.length, n = 0; n < c; n++) {
alert(arr[keys[n]]);
}
For a normal array, I would have done this:
var i = arr.length;
while (i--) {
var value = arr[i];
alert(i =") "+ value);
}
This is faster than a "for" loop.
http://blogs.oracle.com/greimer/entry/best_way_to_code_a
In modern browsers you can now use Object.keys to get your array of properties and step through it in reverse order, allowing you to skip the preliminary key collection loop.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
var keys = Object.keys(subject);
for (var i = keys.length-1; i >= 0; i--) {
var k = keys[i],
v = subject[k];
console.log(k+":",v);
}

Categories

Resources