Monkeypatched code appearing in for...in loop over Array - javascript

I have the following code in my web app's main JavaScript:
// uniq for arrays
if (!Array.prototype.getUnique) {
Array.prototype.getUnique = function () {
var u = {}, a = [];
for (var i = 0, l = this.length; i < l; ++i) {
if (u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
}
}
It's a simple uniq clone for javascript, monkeypatched into the basic Array class. (Not here to debate monkeypatching, flame elsewhere please...)
getUnique() works as intended, but now whenever I iterate over an Array with a for...in loop, an additional index called getUnique is passed to the iterator body, and when this false n is looked up, getUnique's code is the value. (In other words: for...in is looping over the array as it should, but appending a getUnique as the last iteration)
What is going on here? There's another function monkeypatched in right above this one that works fine (indexOf()) and does not appear in the iterator. Here is some example code that triggers this issue:
for (var r in result) {
//tags = tags + result[r]["tags"].split(" ").join(", ")
if (result[r]["tags"]) {
var newtags = result[r]["tags"].split(" ");
debug.log(newtags);
for (var n in newtags) {
debug.log("n is " + n);
tags.push(newtags[n]);
}
}
}
The debug output from this snippet looks like:
[14:22:26.090] [["camp", "furnitur", "wood"]]
[14:22:26.093] ["n is 0"]
[14:22:26.096] ["n is 1"]
[14:22:26.099] ["n is 2"]
[14:22:26.101] ["n is getUnique"]
What is going on here? Refactoring the monkeypatch and dropping it in a utility class is easy enough, but this is a really strange edge case to me. I have some ideas in my head about what is happening here, but those are just guesses. Can anyone explain?

The common misconception is that the for...in operation is, in javascript, made to iterate Arrays. This is wrong. It's usage is to iterate over any enumerable property of an object. In javascript, everything is an object (Arrays included). But you may notice, when you do for...in on an array, you don't get values out like length, slice, etc. This is because those are NOT enumerable properties of the object.
This SO question has some really good information on the usage of for...in: Why is using "for...in" with array iteration a bad idea?
If you want to stick to using for...in, you can do like was suggested above and check for hasOwnProperty inside your for...in
for ( var v in myArray ) {
if ( myArray.hasOwnProperty(v) ) {
// Do Something
}
}
I, however, suggest using plain old boring loops...
for ( var i = 0; i <= myArray.length - 1; i++ ) {
// Do Something
}
Without going into crazy detail, this works without hitting your added methods because the "indexes" of the array are not really indexes at all, but are instead properties with a name that matches their corresponding index: i.e 1, 0, 4, etc.
They feel like indexes because in javascript you can't access a property with dot notation if that property is a number (i.e: myArray.0 will not work). So you do myArray[0], and that feels like an array.

This is what hasOwnProperty is designed to solve: it tells you whether the name you've iterated to is on the object itself, or is inherited from the prototype.
Try this:
for (var n in newtags) {
if (newtags.hasOwnProperty(n)) {
debug.log("n is " + n);
tags.push(newtags[n]);
}
}

You shouldn't iterate over an array using for…in loop, that is intended for enumerating properties of objects. So, for instance, you have no guarantee about the order of the indexes, neither – as you saw – that you're iterate only numeric indexes. If someone else adds a property to the Array's prototype in such way, you will iterate that property as well. See https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in to have the complete picture.
However, in your case, you can do the follow:
for (var n in newtags) {
if (newtags.hasOwnProperty(n)) {
debug.log("n is " + n);
tags.push(newtags[n]);
}
}
That also prevent to iterate properties that are added by other scripts to the prototype. Also, you could define your function as not enumerable (in the browser where ES5 is supported):
Object.defineProperty(Array.prototype, "getUnique", {
value: function () { /*.. your function ..*/}
})
See : https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty

Don't use for-in for iteration of numeric properties.
Use a for loop:
for (var i = 0; i < newtags.length; i++) {
The for-in statement is almost never the right tool for this job, because...
It includes all properties, including non-numeric, out of range, and prototyped properties.
It makes no guarantee of the order of enumeration.
While you could do a hasOwnProperty check, there's no real benefit, and has some down-sides...
It slows down your iteration
It doesn't help with the order of enumeration issue
Sometimes you want a prototyped index (rare, but it happens). Using hasOwnProperty makes this impossible.

Related

Nodejs treating string as a function [duplicate]

I've been told not to use for...in with arrays in JavaScript. Why not?
The reason is that one construct:
var a = []; // Create a new empty array.
a[5] = 5; // Perfectly legal JavaScript that resizes the array.
for (var i = 0; i < a.length; i++) {
// Iterate over numeric indexes from 0 to 5, as everyone expects.
console.log(a[i]);
}
/* Will display:
undefined
undefined
undefined
undefined
undefined
5
*/
can sometimes be totally different from the other:
var a = [];
a[5] = 5;
for (var x in a) {
// Shows only the explicitly set index of "5", and ignores 0-4
console.log(x);
}
/* Will display:
5
*/
Also consider that JavaScript libraries might do things like this, which will affect any array you create:
// Somewhere deep in your JavaScript library...
Array.prototype.foo = 1;
// Now you have no idea what the below code will do.
var a = [1, 2, 3, 4, 5];
for (var x in a){
// Now foo is a part of EVERY array and
// will show up here as a value of 'x'.
console.log(x);
}
/* Will display:
0
1
2
3
4
foo
*/
The for-in statement by itself is not a "bad practice", however it can be mis-used, for example, to iterate over arrays or array-like objects.
The purpose of the for-in statement is to enumerate over object properties. This statement will go up in the prototype chain, also enumerating over inherited properties, a thing that sometimes is not desired.
Also, the order of iteration is not guaranteed by the spec., meaning that if you want to "iterate" an array object, with this statement you cannot be sure that the properties (array indexes) will be visited in the numeric order.
For example, in JScript (IE <= 8), the order of enumeration even on Array objects is defined as the properties were created:
var array = [];
array[2] = 'c';
array[1] = 'b';
array[0] = 'a';
for (var p in array) {
//... p will be "2", "1" and "0" on IE
}
Also, speaking about inherited properties, if you, for example, extend the Array.prototype object (like some libraries as MooTools do), that properties will be also enumerated:
Array.prototype.last = function () { return this[this.length-1]; };
for (var p in []) { // an empty array
// last will be enumerated
}
As I said before to iterate over arrays or array-like objects, the best thing is to use a sequential loop, such as a plain-old for/while loop.
When you want to enumerate only the own properties of an object (the ones that aren't inherited), you can use the hasOwnProperty method:
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
// prop is not inherited
}
}
And some people even recommend calling the method directly from Object.prototype to avoid having problems if somebody adds a property named hasOwnProperty to our object:
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
// prop is not inherited
}
}
There are three reasons why you shouldn't use for..in to iterate over array elements:
for..in will loop over all own and inherited properties of the array object which aren't DontEnum; that means if someone adds properties to the specific array object (there are valid reasons for this - I've done so myself) or changed Array.prototype (which is considered bad practice in code which is supposed to work well with other scripts), these properties will be iterated over as well; inherited properties can be excluded by checking hasOwnProperty(), but that won't help you with properties set in the array object itself
for..in isn't guaranteed to preserve element ordering
it's slow because you have to walk all properties of the array object and its whole prototype chain and will still only get the property's name, ie to get the value, an additional lookup will be required
Because for...in enumerates through the object that holds the array, not the array itself. If I add a function to the arrays prototype chain, that will also be included. I.e.
Array.prototype.myOwnFunction = function() { alert(this); }
a = new Array();
a[0] = 'foo';
a[1] = 'bar';
for(x in a){
document.write(x + ' = ' + a[x]);
}
This will write:
0 = foo
1 = bar
myOwnFunction = function() { alert(this); }
And since you can never be sure that nothing will be added to the prototype chain just use a for loop to enumerate the array:
for(i=0,x=a.length;i<x;i++){
document.write(i + ' = ' + a[i]);
}
This will write:
0 = foo
1 = bar
As of 2016 (ES6) we may use for…of for array iteration, as John Slegers already noticed.
I would just like to add this simple demonstration code, to make things clearer:
Array.prototype.foo = 1;
var arr = [];
arr[5] = "xyz";
console.log("for...of:");
var count = 0;
for (var item of arr) {
console.log(count + ":", item);
count++;
}
console.log("for...in:");
count = 0;
for (var item in arr) {
console.log(count + ":", item);
count++;
}
The console shows:
for...of:
0: undefined
1: undefined
2: undefined
3: undefined
4: undefined
5: xyz
for...in:
0: 5
1: foo
In other words:
for...of counts from 0 to 5, and also ignores Array.prototype.foo. It shows array values.
for...in lists only the 5, ignoring undefined array indexes, but adding foo. It shows array property names.
Short answer: It's just not worth it.
Longer answer: It's just not worth it, even if sequential element order and optimal performance aren't required.
Long answer: It's just not worth it...
Using for (var property in array) will cause array to be iterated over as an object, traversing the object prototype chain and ultimately performing slower than an index-based for loop.
for (... in ...) is not guaranteed to return the object properties in sequential order, as one might expect.
Using hasOwnProperty() and !isNaN() checks to filter the object properties is an additional overhead causing it to perform even slower and negates the key reason for using it in the first place, i.e. because of the more concise format.
For these reasons an acceptable trade-off between performance and convenience doesn't even exist. There's really no benefit unless the intent is to handle the array as an object and perform operations on the object properties of the array.
In isolation, there is nothing wrong with using for-in on arrays. For-in iterates over the property names of an object, and in the case of an "out-of-the-box" array, the properties corresponds to the array indexes. (The built-in propertes like length, toString and so on are not included in the iteration.)
However, if your code (or the framework you are using) add custom properties to arrays or to the array prototype, then these properties will be included in the iteration, which is probably not what you want.
Some JS frameworks, like Prototype modifies the Array prototype. Other frameworks like JQuery doesn't, so with JQuery you can safely use for-in.
If you are in doubt, you probably shouldn't use for-in.
An alternative way of iterating through an array is using a for-loop:
for (var ix=0;ix<arr.length;ix++) alert(ix);
However, this have a different issue. The issue is that a JavaScript array can have "holes". If you define arr as:
var arr = ["hello"];
arr[100] = "goodbye";
Then the array have two items, but a length of 101. Using for-in will yield two indexes, while the for-loop will yield 101 indexes, where the 99 has a value of undefined.
In addition to the reasons given in other answers, you may not want to use the "for...in" structure if you need to do math with the counter variable because the loop iterates through the names of the object's properties and so the variable is a string.
For example,
for (var i=0; i<a.length; i++) {
document.write(i + ', ' + typeof i + ', ' + i+1);
}
will write
0, number, 1
1, number, 2
...
whereas,
for (var ii in a) {
document.write(i + ', ' + typeof i + ', ' + i+1);
}
will write
0, string, 01
1, string, 11
...
Of course, this can easily be overcome by including
ii = parseInt(ii);
in the loop, but the first structure is more direct.
Aside from the fact that for...in loops over all enumerable properties (which is not the same as "all array elements"!), see http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf, section 12.6.4 (5th edition) or 13.7.5.15 (7th edition):
The mechanics and order of enumerating the properties ... is not specified...
(Emphasis mine.)
That means if a browser wanted to, it could go through the properties in the order in which they were inserted. Or in numerical order. Or in lexical order (where "30" comes before "4"! Keep in mind all object keys -- and thus, all array indexes -- are actually strings, so that makes total sense). It could go through them by bucket, if it implemented objects as hash tables. Or take any of that and add "backwards". A browser could even iterate randomly and be ECMA-262 compliant, as long as it visited each property exactly once.
In practice, most browsers currently like to iterate in roughly the same order. But there's nothing saying they have to. That's implementation specific, and could change at any time if another way was found to be far more efficient.
Either way, for...in carries with it no connotation of order. If you care about order, be explicit about it and use a regular for loop with an index.
Mainly two reasons:
One
Like others have said, You might get keys which aren't in your array or that are inherited from the prototype. So if, let's say, a library adds a property to the Array or Object prototypes:
Array.prototype.someProperty = true
You'll get it as part of every array:
for(var item in [1,2,3]){
console.log(item) // will log 1,2,3 but also "someProperty"
}
you could solve this with the hasOwnProperty method:
var ary = [1,2,3];
for(var item in ary){
if(ary.hasOwnProperty(item)){
console.log(item) // will log only 1,2,3
}
}
but this is true for iterating over any object with a for-in loop.
Two
Usually the order of the items in an array is important, but the for-in loop won't necessarily iterate in the right order, that's because it treats the array as an object, which is the way it is implemented in JS, and not as an array.
This seems like a small thing, but it can really screw up applications and is hard to debug.
I don't think I have much to add to eg. Triptych's answer or CMS's answer on why using for...in should be avoided in some cases.
I do, however, would like to add that in modern browsers there is an alternative to for...in that can be used in those cases where for...in can't be used. That alternative is for...of :
for (var item of items) {
console.log(item);
}
Note :
Unfortunately, no version of Internet Explorer supports for...of (Edge 12+ does), so you'll have to wait a bit longer until you can use it in your client side production code. However, it should be safe to use in your server side JS code (if you use Node.js).
Because it enumerates through object fields, not indexes. You can get value with index "length" and I doubt you want this.
The problem with for ... in ... — and this only becomes a problem when a programmer doesn't really understand the language; it's not really a bug or anything — is that it iterates over all members of an object (well, all enumerable members, but that's a detail for now). When you want to iterate over just the indexed properties of an array, the only guaranteed way to keep things semantically consistent is to use an integer index (that is, a for (var i = 0; i < array.length; ++i) style loop).
Any object can have arbitrary properties associated with it. There would be nothing terrible about loading additional properties onto an array instance, in particular. Code that wants to see only indexed array-like properties therefore must stick to an integer index. Code that is fully aware of what for ... in does and really need to see all properties, well then that's ok too.
TL&DR: Using the for in loop in arrays is not evil, in fact quite the opposite.
I think the for in loop is a gem of JS if used correctly in arrays. You are expected to have full control over your software and know what you are doing. Let's see the mentioned drawbacks and disprove them one by one.
It loops through inherited properties as well: First of all any extensions to the Array.prototype should have been done by using Object.defineProperty() and their enumerable descriptor should be set to false. Any library not doing so should not be used at all.
Properties those you add to the inheritance chain later get counted: When doing array sub-classing by Object.setPrototypeOf or by Class extend. You should again use Object.defineProperty() which by default sets the writable, enumerable and configurable property descriptors to false. Lets see an array sub-classing example here...
function Stack(...a){
var stack = new Array(...a);
Object.setPrototypeOf(stack, Stack.prototype);
return stack;
}
Stack.prototype = Object.create(Array.prototype); // now stack has full access to array methods.
Object.defineProperty(Stack.prototype,"constructor",{value:Stack}); // now Stack is a proper constructor
Object.defineProperty(Stack.prototype,"peak",{value: function(){ // add Stack "only" methods to the Stack.prototype.
return this[this.length-1];
}
});
var s = new Stack(1,2,3,4,1);
console.log(s.peak());
s[s.length] = 7;
console.log("length:",s.length);
s.push(42);
console.log(JSON.stringify(s));
console.log("length:",s.length);
for(var i in s) console.log(s[i]);
So you see.. for in loop is now safe since you cared about your code.
The for in loop is slow: Hell no. It's by far the fastest method of iteration if you are looping over sparse arrays which are needed time to time. This is one of the most important performance tricks that one should know. Let's see an example. We will loop over a sparse array.
var a = [];
a[0] = "zero";
a[10000000] = "ten million";
console.time("for loop on array a:");
for(var i=0; i < a.length; i++) a[i] && console.log(a[i]);
console.timeEnd("for loop on array a:");
console.time("for in loop on array a:");
for(var i in a) a[i] && console.log(a[i]);
console.timeEnd("for in loop on array a:");
Also, due to semantics, the way for, in treats arrays (i.e. the same as any other JavaScript object) is not aligned with other popular languages.
// C#
char[] a = new char[] {'A', 'B', 'C'};
foreach (char x in a) System.Console.Write(x); //Output: "ABC"
// Java
char[] a = {'A', 'B', 'C'};
for (char x : a) System.out.print(x); //Output: "ABC"
// PHP
$a = array('A', 'B', 'C');
foreach ($a as $x) echo $x; //Output: "ABC"
// JavaScript
var a = ['A', 'B', 'C'];
for (var x in a) document.write(x); //Output: "012"
Here are the reasons why this is (usually) a bad practice:
for...in loops iterate over all their own enumerable properties and the enumerable properties of their prototype(s). Usually in an array iteration we only want to iterate over the array itself. And even though you yourself may not add anything to the array, your libraries or framework might add something.
Example:
Array.prototype.hithere = 'hithere';
var array = [1, 2, 3];
for (let el in array){
// the hithere property will also be iterated over
console.log(el);
}
for...in loops do not guarantee a specific iteration order. Although is order is usually seen in most modern browsers these days, there is still no 100% guarantee.
for...in loops ignore undefined array elements, i.e. array elements which not have been assigned yet.
Example::
const arr = [];
arr[3] = 'foo'; // resize the array to 4
arr[4] = undefined; // add another element with value undefined to it
// iterate over the array, a for loop does show the undefined elements
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
console.log('\n');
// for in does ignore the undefined elements
for (let el in arr) {
console.log(arr[el]);
}
In addition to the other problems, the "for..in" syntax is probably slower, because the index is a string, not an integer.
var a = ["a"]
for (var i in a)
alert(typeof i) // 'string'
for (var i = 0; i < a.length; i++)
alert(typeof i) // 'number'
An important aspect is that for...in only iterates over properties contained in an object which have their enumerable property attribute set to true. So if one attempts to iterate over an object using for...in then arbitrary properties may be missed if their enumerable property attribute is false. It is quite possible to alter the enumerable property attribute for normal Array objects so that certain elements are not enumerated. Though in general the property attributes tend to apply to function properties within an object.
One can check the value of a properties' enumerable property attribute by:
myobject.propertyIsEnumerable('myproperty')
Or to obtain all four property attributes:
Object.getOwnPropertyDescriptor(myobject,'myproperty')
This is a feature available in ECMAScript 5 - in earlier versions it was not possible to alter the value of the enumerable property attribute (it was always set to true).
The for/in works with two types of variables: hashtables (associative arrays) and array (non-associative).
JavaScript will automatically determine the way its passes through the items. So if you know that your array is really non-associative you can use for (var i=0; i<=arrayLen; i++), and skip the auto-detection iteration.
But in my opinion, it's better to use for/in, the process required for that auto-detection is very small.
A real answer for this will depend on how the browser parsers/interpret the JavaScript code. It can change between browsers.
I can't think of other purposes to not using for/in;
//Non-associative
var arr = ['a', 'b', 'c'];
for (var i in arr)
alert(arr[i]);
//Associative
var arr = {
item1 : 'a',
item2 : 'b',
item3 : 'c'
};
for (var i in arr)
alert(arr[i]);
Because it will iterate over properties belonging to objects up the prototype chain if you're not careful.
You can use for.. in, just be sure to check each property with hasOwnProperty.
It's not necessarily bad (based on what you're doing), but in the case of arrays, if something has been added to Array.prototype, then you're going to get strange results. Where you'd expect this loop to run three times:
var arr = ['a','b','c'];
for (var key in arr) { ... }
If a function called helpfulUtilityMethod has been added to Array's prototype, then your loop would end up running four times: key would be 0, 1, 2, and helpfulUtilityMethod. If you were only expecting integers, oops.
You should use the for(var x in y) only on property lists, not on objects (as explained above).
Using the for...in loop for an array is not wrong, although I can guess why someone told you that:
1.) There is already a higher order function, or method, that has that purpose for an array, but has more functionality and leaner syntax, called 'forEach': Array.prototype.forEach(function(element, index, array) {} );
2.) Arrays always have a length, but for...in and forEach do not execute a function for any value that is 'undefined', only for the indexes that have a value defined. So if you only assign one value, these loops will only execute a function once, but since an array is enumerated, it will always have a length up to the highest index that has a defined value, but that length could go unnoticed when using these loops.
3.) The standard for loop will execute a function as many times as you define in the parameters, and since an array is numbered, it makes more sense to define how many times you want to execute a function. Unlike the other loops, the for loop can then execute a function for every index in the array, whether the value is defined or not.
In essence, you can use any loop, but you should remember exactly how they work. Understand the conditions upon which the different loops reiterate, their separate functionalities, and realize they will be more or less appropriate for differing scenarios.
Also, it may be considered a better practice to use the forEach method than the for...in loop in general, because it is easier to write and has more functionality, so you may want to get in the habit of only using this method and standard for, but your call.
See below that the first two loops only execute the console.log statements once, while the standard for loop executes the function as many times as specified, in this case, array.length = 6.
var arr = [];
arr[5] = 'F';
for (var index in arr) {
console.log(index);
console.log(arr[index]);
console.log(arr)
}
// 5
// 'F'
// => (6) [undefined x 5, 6]
arr.forEach(function(element, index, arr) {
console.log(index);
console.log(element);
console.log(arr);
});
// 5
// 'F'
// => Array (6) [undefined x 5, 6]
for (var index = 0; index < arr.length; index++) {
console.log(index);
console.log(arr[index]);
console.log(arr);
};
// 0
// undefined
// => Array (6) [undefined x 5, 6]
// 1
// undefined
// => Array (6) [undefined x 5, 6]
// 2
// undefined
// => Array (6) [undefined x 5, 6]
// 3
// undefined
// => Array (6) [undefined x 5, 6]
// 4
// undefined
// => Array (6) [undefined x 5, 6]
// 5
// 'F'
// => Array (6) [undefined x 5, 6]
A for...in loop always enumerates the keys.
Objects properties keys are always String, even the indexed properties of an array :
var myArray = ['a', 'b', 'c', 'd'];
var total = 0
for (elem in myArray) {
total += elem
}
console.log(total); // 00123
for...in is useful when working on an object in JavaScript, but not for an Array, but still we can not say it's a wrong way, but it's not recommended, look at this example below using for...in loop:
let txt = "";
const person = {fname:"Alireza", lname:"Dezfoolian", age:35};
for (const x in person) {
txt += person[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35
OK, let's do it with Array now:
let txt = "";
const person = ["Alireza", "Dezfoolian", 35];
for (const x in person) {
txt += person[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35
As you see the result the same...
But let's try something, let's prototype something to Array...
Array.prototype.someoneelse = "someoneelse";
Now we create a new Array();
let txt = "";
const arr = new Array();
arr[0] = 'Alireza';
arr[1] = 'Dezfoolian';
arr[2] = 35;
for(x in arr) {
txt += arr[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35 someoneelse
You see the someoneelse!!!... We actually looping through new Array object in this case!
So that's one of the reasons why we need to use for..in carefully, but it's not always the case...
Since JavaScript elements are saved as standard object properties, it
is not advisable to iterate through JavaScript arrays using for...in
loops because normal elements and all enumerable properties will be
listed.
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections
although not specifically addressed by this question, I would add that there's a very good reason not to ever use for...in with a NodeList (as one would obtain from a querySelectorAll call, as it doesn't see the returned elements at all, instead iterating only over the NodeList properties.
in the case of a single result, I got:
var nodes = document.querySelectorAll(selector);
nodes
▶ NodeList [a._19eb]
for (node in nodes) {console.log(node)};
VM505:1 0
VM505:1 length
VM505:1 item
VM505:1 entries
VM505:1 forEach
VM505:1 keys
VM505:1 values
which explained why my for (node in nodes) node.href = newLink; was failing.
for in loop converts the indices to string when traversing through an array.
For example, In the below code, in the second loop where initialising j with i+1, i is the index but in a string ("0", "1" etc) and number + string in js is a string. if js encounters "0" + 1 it will return "01".
var maxProfit = function(prices) {
let maxProfit = 0;
for (let i in prices) {
for (let j = i + 1; j < prices.length; j++) {
console.log(prices[j] - prices[i], "i,j", i, j, typeof i, typeof j);
if ((prices[j] - prices[i]) > maxProfit) maxProfit = (prices[j] - prices[i]);
}
}
return maxProfit;
};
maxProfit([7, 1, 5, 3, 6, 4]);

why giveing extra element when use for...in javascript [duplicate]

I've been told not to use for...in with arrays in JavaScript. Why not?
The reason is that one construct:
var a = []; // Create a new empty array.
a[5] = 5; // Perfectly legal JavaScript that resizes the array.
for (var i = 0; i < a.length; i++) {
// Iterate over numeric indexes from 0 to 5, as everyone expects.
console.log(a[i]);
}
/* Will display:
undefined
undefined
undefined
undefined
undefined
5
*/
can sometimes be totally different from the other:
var a = [];
a[5] = 5;
for (var x in a) {
// Shows only the explicitly set index of "5", and ignores 0-4
console.log(x);
}
/* Will display:
5
*/
Also consider that JavaScript libraries might do things like this, which will affect any array you create:
// Somewhere deep in your JavaScript library...
Array.prototype.foo = 1;
// Now you have no idea what the below code will do.
var a = [1, 2, 3, 4, 5];
for (var x in a){
// Now foo is a part of EVERY array and
// will show up here as a value of 'x'.
console.log(x);
}
/* Will display:
0
1
2
3
4
foo
*/
The for-in statement by itself is not a "bad practice", however it can be mis-used, for example, to iterate over arrays or array-like objects.
The purpose of the for-in statement is to enumerate over object properties. This statement will go up in the prototype chain, also enumerating over inherited properties, a thing that sometimes is not desired.
Also, the order of iteration is not guaranteed by the spec., meaning that if you want to "iterate" an array object, with this statement you cannot be sure that the properties (array indexes) will be visited in the numeric order.
For example, in JScript (IE <= 8), the order of enumeration even on Array objects is defined as the properties were created:
var array = [];
array[2] = 'c';
array[1] = 'b';
array[0] = 'a';
for (var p in array) {
//... p will be "2", "1" and "0" on IE
}
Also, speaking about inherited properties, if you, for example, extend the Array.prototype object (like some libraries as MooTools do), that properties will be also enumerated:
Array.prototype.last = function () { return this[this.length-1]; };
for (var p in []) { // an empty array
// last will be enumerated
}
As I said before to iterate over arrays or array-like objects, the best thing is to use a sequential loop, such as a plain-old for/while loop.
When you want to enumerate only the own properties of an object (the ones that aren't inherited), you can use the hasOwnProperty method:
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
// prop is not inherited
}
}
And some people even recommend calling the method directly from Object.prototype to avoid having problems if somebody adds a property named hasOwnProperty to our object:
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
// prop is not inherited
}
}
There are three reasons why you shouldn't use for..in to iterate over array elements:
for..in will loop over all own and inherited properties of the array object which aren't DontEnum; that means if someone adds properties to the specific array object (there are valid reasons for this - I've done so myself) or changed Array.prototype (which is considered bad practice in code which is supposed to work well with other scripts), these properties will be iterated over as well; inherited properties can be excluded by checking hasOwnProperty(), but that won't help you with properties set in the array object itself
for..in isn't guaranteed to preserve element ordering
it's slow because you have to walk all properties of the array object and its whole prototype chain and will still only get the property's name, ie to get the value, an additional lookup will be required
Because for...in enumerates through the object that holds the array, not the array itself. If I add a function to the arrays prototype chain, that will also be included. I.e.
Array.prototype.myOwnFunction = function() { alert(this); }
a = new Array();
a[0] = 'foo';
a[1] = 'bar';
for(x in a){
document.write(x + ' = ' + a[x]);
}
This will write:
0 = foo
1 = bar
myOwnFunction = function() { alert(this); }
And since you can never be sure that nothing will be added to the prototype chain just use a for loop to enumerate the array:
for(i=0,x=a.length;i<x;i++){
document.write(i + ' = ' + a[i]);
}
This will write:
0 = foo
1 = bar
As of 2016 (ES6) we may use for…of for array iteration, as John Slegers already noticed.
I would just like to add this simple demonstration code, to make things clearer:
Array.prototype.foo = 1;
var arr = [];
arr[5] = "xyz";
console.log("for...of:");
var count = 0;
for (var item of arr) {
console.log(count + ":", item);
count++;
}
console.log("for...in:");
count = 0;
for (var item in arr) {
console.log(count + ":", item);
count++;
}
The console shows:
for...of:
0: undefined
1: undefined
2: undefined
3: undefined
4: undefined
5: xyz
for...in:
0: 5
1: foo
In other words:
for...of counts from 0 to 5, and also ignores Array.prototype.foo. It shows array values.
for...in lists only the 5, ignoring undefined array indexes, but adding foo. It shows array property names.
Short answer: It's just not worth it.
Longer answer: It's just not worth it, even if sequential element order and optimal performance aren't required.
Long answer: It's just not worth it...
Using for (var property in array) will cause array to be iterated over as an object, traversing the object prototype chain and ultimately performing slower than an index-based for loop.
for (... in ...) is not guaranteed to return the object properties in sequential order, as one might expect.
Using hasOwnProperty() and !isNaN() checks to filter the object properties is an additional overhead causing it to perform even slower and negates the key reason for using it in the first place, i.e. because of the more concise format.
For these reasons an acceptable trade-off between performance and convenience doesn't even exist. There's really no benefit unless the intent is to handle the array as an object and perform operations on the object properties of the array.
In isolation, there is nothing wrong with using for-in on arrays. For-in iterates over the property names of an object, and in the case of an "out-of-the-box" array, the properties corresponds to the array indexes. (The built-in propertes like length, toString and so on are not included in the iteration.)
However, if your code (or the framework you are using) add custom properties to arrays or to the array prototype, then these properties will be included in the iteration, which is probably not what you want.
Some JS frameworks, like Prototype modifies the Array prototype. Other frameworks like JQuery doesn't, so with JQuery you can safely use for-in.
If you are in doubt, you probably shouldn't use for-in.
An alternative way of iterating through an array is using a for-loop:
for (var ix=0;ix<arr.length;ix++) alert(ix);
However, this have a different issue. The issue is that a JavaScript array can have "holes". If you define arr as:
var arr = ["hello"];
arr[100] = "goodbye";
Then the array have two items, but a length of 101. Using for-in will yield two indexes, while the for-loop will yield 101 indexes, where the 99 has a value of undefined.
In addition to the reasons given in other answers, you may not want to use the "for...in" structure if you need to do math with the counter variable because the loop iterates through the names of the object's properties and so the variable is a string.
For example,
for (var i=0; i<a.length; i++) {
document.write(i + ', ' + typeof i + ', ' + i+1);
}
will write
0, number, 1
1, number, 2
...
whereas,
for (var ii in a) {
document.write(i + ', ' + typeof i + ', ' + i+1);
}
will write
0, string, 01
1, string, 11
...
Of course, this can easily be overcome by including
ii = parseInt(ii);
in the loop, but the first structure is more direct.
Aside from the fact that for...in loops over all enumerable properties (which is not the same as "all array elements"!), see http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf, section 12.6.4 (5th edition) or 13.7.5.15 (7th edition):
The mechanics and order of enumerating the properties ... is not specified...
(Emphasis mine.)
That means if a browser wanted to, it could go through the properties in the order in which they were inserted. Or in numerical order. Or in lexical order (where "30" comes before "4"! Keep in mind all object keys -- and thus, all array indexes -- are actually strings, so that makes total sense). It could go through them by bucket, if it implemented objects as hash tables. Or take any of that and add "backwards". A browser could even iterate randomly and be ECMA-262 compliant, as long as it visited each property exactly once.
In practice, most browsers currently like to iterate in roughly the same order. But there's nothing saying they have to. That's implementation specific, and could change at any time if another way was found to be far more efficient.
Either way, for...in carries with it no connotation of order. If you care about order, be explicit about it and use a regular for loop with an index.
Mainly two reasons:
One
Like others have said, You might get keys which aren't in your array or that are inherited from the prototype. So if, let's say, a library adds a property to the Array or Object prototypes:
Array.prototype.someProperty = true
You'll get it as part of every array:
for(var item in [1,2,3]){
console.log(item) // will log 1,2,3 but also "someProperty"
}
you could solve this with the hasOwnProperty method:
var ary = [1,2,3];
for(var item in ary){
if(ary.hasOwnProperty(item)){
console.log(item) // will log only 1,2,3
}
}
but this is true for iterating over any object with a for-in loop.
Two
Usually the order of the items in an array is important, but the for-in loop won't necessarily iterate in the right order, that's because it treats the array as an object, which is the way it is implemented in JS, and not as an array.
This seems like a small thing, but it can really screw up applications and is hard to debug.
I don't think I have much to add to eg. Triptych's answer or CMS's answer on why using for...in should be avoided in some cases.
I do, however, would like to add that in modern browsers there is an alternative to for...in that can be used in those cases where for...in can't be used. That alternative is for...of :
for (var item of items) {
console.log(item);
}
Note :
Unfortunately, no version of Internet Explorer supports for...of (Edge 12+ does), so you'll have to wait a bit longer until you can use it in your client side production code. However, it should be safe to use in your server side JS code (if you use Node.js).
Because it enumerates through object fields, not indexes. You can get value with index "length" and I doubt you want this.
The problem with for ... in ... — and this only becomes a problem when a programmer doesn't really understand the language; it's not really a bug or anything — is that it iterates over all members of an object (well, all enumerable members, but that's a detail for now). When you want to iterate over just the indexed properties of an array, the only guaranteed way to keep things semantically consistent is to use an integer index (that is, a for (var i = 0; i < array.length; ++i) style loop).
Any object can have arbitrary properties associated with it. There would be nothing terrible about loading additional properties onto an array instance, in particular. Code that wants to see only indexed array-like properties therefore must stick to an integer index. Code that is fully aware of what for ... in does and really need to see all properties, well then that's ok too.
TL&DR: Using the for in loop in arrays is not evil, in fact quite the opposite.
I think the for in loop is a gem of JS if used correctly in arrays. You are expected to have full control over your software and know what you are doing. Let's see the mentioned drawbacks and disprove them one by one.
It loops through inherited properties as well: First of all any extensions to the Array.prototype should have been done by using Object.defineProperty() and their enumerable descriptor should be set to false. Any library not doing so should not be used at all.
Properties those you add to the inheritance chain later get counted: When doing array sub-classing by Object.setPrototypeOf or by Class extend. You should again use Object.defineProperty() which by default sets the writable, enumerable and configurable property descriptors to false. Lets see an array sub-classing example here...
function Stack(...a){
var stack = new Array(...a);
Object.setPrototypeOf(stack, Stack.prototype);
return stack;
}
Stack.prototype = Object.create(Array.prototype); // now stack has full access to array methods.
Object.defineProperty(Stack.prototype,"constructor",{value:Stack}); // now Stack is a proper constructor
Object.defineProperty(Stack.prototype,"peak",{value: function(){ // add Stack "only" methods to the Stack.prototype.
return this[this.length-1];
}
});
var s = new Stack(1,2,3,4,1);
console.log(s.peak());
s[s.length] = 7;
console.log("length:",s.length);
s.push(42);
console.log(JSON.stringify(s));
console.log("length:",s.length);
for(var i in s) console.log(s[i]);
So you see.. for in loop is now safe since you cared about your code.
The for in loop is slow: Hell no. It's by far the fastest method of iteration if you are looping over sparse arrays which are needed time to time. This is one of the most important performance tricks that one should know. Let's see an example. We will loop over a sparse array.
var a = [];
a[0] = "zero";
a[10000000] = "ten million";
console.time("for loop on array a:");
for(var i=0; i < a.length; i++) a[i] && console.log(a[i]);
console.timeEnd("for loop on array a:");
console.time("for in loop on array a:");
for(var i in a) a[i] && console.log(a[i]);
console.timeEnd("for in loop on array a:");
Also, due to semantics, the way for, in treats arrays (i.e. the same as any other JavaScript object) is not aligned with other popular languages.
// C#
char[] a = new char[] {'A', 'B', 'C'};
foreach (char x in a) System.Console.Write(x); //Output: "ABC"
// Java
char[] a = {'A', 'B', 'C'};
for (char x : a) System.out.print(x); //Output: "ABC"
// PHP
$a = array('A', 'B', 'C');
foreach ($a as $x) echo $x; //Output: "ABC"
// JavaScript
var a = ['A', 'B', 'C'];
for (var x in a) document.write(x); //Output: "012"
Here are the reasons why this is (usually) a bad practice:
for...in loops iterate over all their own enumerable properties and the enumerable properties of their prototype(s). Usually in an array iteration we only want to iterate over the array itself. And even though you yourself may not add anything to the array, your libraries or framework might add something.
Example:
Array.prototype.hithere = 'hithere';
var array = [1, 2, 3];
for (let el in array){
// the hithere property will also be iterated over
console.log(el);
}
for...in loops do not guarantee a specific iteration order. Although is order is usually seen in most modern browsers these days, there is still no 100% guarantee.
for...in loops ignore undefined array elements, i.e. array elements which not have been assigned yet.
Example::
const arr = [];
arr[3] = 'foo'; // resize the array to 4
arr[4] = undefined; // add another element with value undefined to it
// iterate over the array, a for loop does show the undefined elements
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
console.log('\n');
// for in does ignore the undefined elements
for (let el in arr) {
console.log(arr[el]);
}
In addition to the other problems, the "for..in" syntax is probably slower, because the index is a string, not an integer.
var a = ["a"]
for (var i in a)
alert(typeof i) // 'string'
for (var i = 0; i < a.length; i++)
alert(typeof i) // 'number'
An important aspect is that for...in only iterates over properties contained in an object which have their enumerable property attribute set to true. So if one attempts to iterate over an object using for...in then arbitrary properties may be missed if their enumerable property attribute is false. It is quite possible to alter the enumerable property attribute for normal Array objects so that certain elements are not enumerated. Though in general the property attributes tend to apply to function properties within an object.
One can check the value of a properties' enumerable property attribute by:
myobject.propertyIsEnumerable('myproperty')
Or to obtain all four property attributes:
Object.getOwnPropertyDescriptor(myobject,'myproperty')
This is a feature available in ECMAScript 5 - in earlier versions it was not possible to alter the value of the enumerable property attribute (it was always set to true).
The for/in works with two types of variables: hashtables (associative arrays) and array (non-associative).
JavaScript will automatically determine the way its passes through the items. So if you know that your array is really non-associative you can use for (var i=0; i<=arrayLen; i++), and skip the auto-detection iteration.
But in my opinion, it's better to use for/in, the process required for that auto-detection is very small.
A real answer for this will depend on how the browser parsers/interpret the JavaScript code. It can change between browsers.
I can't think of other purposes to not using for/in;
//Non-associative
var arr = ['a', 'b', 'c'];
for (var i in arr)
alert(arr[i]);
//Associative
var arr = {
item1 : 'a',
item2 : 'b',
item3 : 'c'
};
for (var i in arr)
alert(arr[i]);
Because it will iterate over properties belonging to objects up the prototype chain if you're not careful.
You can use for.. in, just be sure to check each property with hasOwnProperty.
It's not necessarily bad (based on what you're doing), but in the case of arrays, if something has been added to Array.prototype, then you're going to get strange results. Where you'd expect this loop to run three times:
var arr = ['a','b','c'];
for (var key in arr) { ... }
If a function called helpfulUtilityMethod has been added to Array's prototype, then your loop would end up running four times: key would be 0, 1, 2, and helpfulUtilityMethod. If you were only expecting integers, oops.
You should use the for(var x in y) only on property lists, not on objects (as explained above).
Using the for...in loop for an array is not wrong, although I can guess why someone told you that:
1.) There is already a higher order function, or method, that has that purpose for an array, but has more functionality and leaner syntax, called 'forEach': Array.prototype.forEach(function(element, index, array) {} );
2.) Arrays always have a length, but for...in and forEach do not execute a function for any value that is 'undefined', only for the indexes that have a value defined. So if you only assign one value, these loops will only execute a function once, but since an array is enumerated, it will always have a length up to the highest index that has a defined value, but that length could go unnoticed when using these loops.
3.) The standard for loop will execute a function as many times as you define in the parameters, and since an array is numbered, it makes more sense to define how many times you want to execute a function. Unlike the other loops, the for loop can then execute a function for every index in the array, whether the value is defined or not.
In essence, you can use any loop, but you should remember exactly how they work. Understand the conditions upon which the different loops reiterate, their separate functionalities, and realize they will be more or less appropriate for differing scenarios.
Also, it may be considered a better practice to use the forEach method than the for...in loop in general, because it is easier to write and has more functionality, so you may want to get in the habit of only using this method and standard for, but your call.
See below that the first two loops only execute the console.log statements once, while the standard for loop executes the function as many times as specified, in this case, array.length = 6.
var arr = [];
arr[5] = 'F';
for (var index in arr) {
console.log(index);
console.log(arr[index]);
console.log(arr)
}
// 5
// 'F'
// => (6) [undefined x 5, 6]
arr.forEach(function(element, index, arr) {
console.log(index);
console.log(element);
console.log(arr);
});
// 5
// 'F'
// => Array (6) [undefined x 5, 6]
for (var index = 0; index < arr.length; index++) {
console.log(index);
console.log(arr[index]);
console.log(arr);
};
// 0
// undefined
// => Array (6) [undefined x 5, 6]
// 1
// undefined
// => Array (6) [undefined x 5, 6]
// 2
// undefined
// => Array (6) [undefined x 5, 6]
// 3
// undefined
// => Array (6) [undefined x 5, 6]
// 4
// undefined
// => Array (6) [undefined x 5, 6]
// 5
// 'F'
// => Array (6) [undefined x 5, 6]
A for...in loop always enumerates the keys.
Objects properties keys are always String, even the indexed properties of an array :
var myArray = ['a', 'b', 'c', 'd'];
var total = 0
for (elem in myArray) {
total += elem
}
console.log(total); // 00123
for...in is useful when working on an object in JavaScript, but not for an Array, but still we can not say it's a wrong way, but it's not recommended, look at this example below using for...in loop:
let txt = "";
const person = {fname:"Alireza", lname:"Dezfoolian", age:35};
for (const x in person) {
txt += person[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35
OK, let's do it with Array now:
let txt = "";
const person = ["Alireza", "Dezfoolian", 35];
for (const x in person) {
txt += person[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35
As you see the result the same...
But let's try something, let's prototype something to Array...
Array.prototype.someoneelse = "someoneelse";
Now we create a new Array();
let txt = "";
const arr = new Array();
arr[0] = 'Alireza';
arr[1] = 'Dezfoolian';
arr[2] = 35;
for(x in arr) {
txt += arr[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35 someoneelse
You see the someoneelse!!!... We actually looping through new Array object in this case!
So that's one of the reasons why we need to use for..in carefully, but it's not always the case...
Since JavaScript elements are saved as standard object properties, it
is not advisable to iterate through JavaScript arrays using for...in
loops because normal elements and all enumerable properties will be
listed.
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections
although not specifically addressed by this question, I would add that there's a very good reason not to ever use for...in with a NodeList (as one would obtain from a querySelectorAll call, as it doesn't see the returned elements at all, instead iterating only over the NodeList properties.
in the case of a single result, I got:
var nodes = document.querySelectorAll(selector);
nodes
▶ NodeList [a._19eb]
for (node in nodes) {console.log(node)};
VM505:1 0
VM505:1 length
VM505:1 item
VM505:1 entries
VM505:1 forEach
VM505:1 keys
VM505:1 values
which explained why my for (node in nodes) node.href = newLink; was failing.
for in loop converts the indices to string when traversing through an array.
For example, In the below code, in the second loop where initialising j with i+1, i is the index but in a string ("0", "1" etc) and number + string in js is a string. if js encounters "0" + 1 it will return "01".
var maxProfit = function(prices) {
let maxProfit = 0;
for (let i in prices) {
for (let j = i + 1; j < prices.length; j++) {
console.log(prices[j] - prices[i], "i,j", i, j, typeof i, typeof j);
if ((prices[j] - prices[i]) > maxProfit) maxProfit = (prices[j] - prices[i]);
}
}
return maxProfit;
};
maxProfit([7, 1, 5, 3, 6, 4]);

How to loop over an Array with JavaScript?

I have a string that has data separated by a pipe character (|).
Example
var somestring = "data1|data2|data3";
var separated = somestring.split("|");
I know how to use the split() to separate each data.
However, I don't know how many pipes there will be in the resulting Array.
In jQuery or JavaScript, how do I loop over the array returned?
In jQuery or JavaScript, how do I loop through each separated variable?
You basically just need to iterate over the resulting Array.
jQuery
$.each loop
This method is easy to work with, and benefits in the variables used being encapsulated.
$.each(separated, function(index, chunk) {
// `chunk` is each member of the array.
});
jsFiddle.
Of course, jQuery is JavaScript so any of the below methods will also work.
JavaScript
for loop
This is the recommended way.
for (var i = 0, length = separated.length; i < length; i++) {
var chunk = separated[i];
// `chunk` is each member of the array.
}
jsFiddle.
You'll notice too the length property is cached so it is not looked up on each iteration. Some browsers already optimise for this, however IE appears to still benefit from it cached. It only takes 5 seconds to do, so you may as well keep IE users happy too.
You may want to define i and chunk outside of the for loop, because JavaScript has no block scope (unless you're using let), and those variables will exist before (declaration hoisted) and after (no block scope).
for ( in ) loop
This loop is generally not recommended, as it should be used for iterating over object properties only, not array like member properties.
for (var chunk in separated) {
if ( ! separated.hasOwnProperty(chunk)) {
continue;
}
// `separated[chunk]` is each member of the array.
}
jsFiddle.
This loop will loop over all properties up the prototype chain, so hasOwnProperty() must be used. For this reason it is not recommended for arrays.
for ( of ) loop
This loop is standardized in ECMA 6 and is able to loop over NodeLists and iterators.
for (var chunk of separated) {
// `chunk` is each member of the array.
}
jsFiddle
forEach() method
This method is an addition to the ECMA-262 standard. It's not available in IE8, but it can be shimmed relatively easily.
separated.forEach(function(chunk, index) {
// `chunk` is each member of the array.
});
jsFiddle.
Other specialised methods
If you're looking to iterate for a specific goal, it may be useful to use a specialised iterator. Keep in mind these also don't have the best browser support.
filter method
Creates a mew array of the elements which the associated callback returned truthy for.
separated.filter(function(element) {
return +element > 255;
});
reduce method
Creates a new value based on reducing the elements of the array, from left to right.
separated.reduce(function(accumulator, element) {
return accumulator.concat(element);
}, "");
See also the reduceRight method.
map method
Creates a new array, replacing each element with the returned value of the associated callback.
separated.map(function(element) {
return element.substr(0, 1);
});
every method
Returns a boolean value of which is the result of every element in the array passing the test. This method short circuits, i.e. it returns whenever one element's callback doesn't return truthy.
separated.every(function(element) {
return element.substr(0, 1) == "a";
});
some method
Returns a boolean value of which is the result of some element in the array passing the test. This method short circuits, i.e. it returns whenever one element's callback passes the test.
separated.some(function(element) {
return element.substr(0, 1) == "a";
});
separated.length should be all you need.
str.split() returns an array of values, so in your example, since 'separated' is an array, you could:
for (var i=0, len=separated.length; i < len; i++) {
// do something with separated[i]
}
you can do it in jquery like this
$.each(separated,function(key,item){ alert('here is ' + item + ' at position ' + key) })
If your question really is "how do I loop through each separated variable?" then:
for (var i = 0; i < separated.length; i++)
{
//Do something with separated[i];
}
//or (apparently this is deprecated)
for(var a in separated)
{
//Do something with a
}
Loop through with a FOR...NEXT construct like in most other languages:
var somestring = "data1|data2|data3";
var separated = somestring.split("|");
for (i=0 ; i<separated.length; i++) {
document.write(separated[i]);
document.write("<br/>");
}

Javascript for...in statement gives error when looping through array

I just tried the for...in statement in Javascript.
This gives no error:
var images = document.getElementsByTagName('img');
for(x in images){
document.write(images[x]) + " ");
}
However, this does what it should but gives an error in the FF error console.
for(x in images){
images[x].style.visibility="visible";
}
This made me VERY curious as to what's going on.
Doing this:
for(x in images){
document.write(x);
}
...gave me this:
01234567891011121314151617lengthitemnamedItem
What's there at the end? I assume this makes the document.images / document.getElementsByTagName('img') array not suitable to use with the for...in statement since the values for x at the end won't correspond to an image? Maybe a for loop is better?
Don't iterate through arrays with for ... in loops. Use an index:
for (var i = 0; i < arr.length; ++i) {
// images[i] ...
}
The for ... in construct isn't wrong, it's just not what you want to do; it's for when you want to iterate through all properties of an object. Arrays are objects, and there are other properties besides the semantically-interesting indexed elements.
(Actually what comes back from getElementsByTagName isn't really an Array; it's a node list. You can however treat it like an array and it'll generally work OK. The same basic caveat applies for for ... in in any case.)
for..in does not loop through the indexes of an array, it loops through the enumerable property names of an object. It happens that the only enumerable properties array instances have, by default, are array indexes, and so it mostly works to think it does array indexes in limited situations. But that's not what for..in does, and misunderstanding this will bite you. :-) It breaks as soon as you add any further properties to the array (a perfectly valid thing to do) or any library you're using decides to extend the array prototype (also a valid thing to do).
In any case, what you get back from document.getElementsByTagName isn't an array. It's a NodeList. Your best bet for iterating through NodeLists is to use an explicit index a'la Pointy's answer -- e.g., a straight counting loop:
var i;
for (i = 0; i < list.length; ++i) {
// ... do your thing ...
}
Somewhat off-topic because it doesn't relate to your NodeList, but: When you are actually working with a real array, because arrays in JavaScript are sparse, there is applicability for for..in, you just have to be clear about what you're doing (looping through property names, not indexes). You might want to loop only as many times as the array has actual entries, rather than looping through all the indexes in the gaps in the sparse array. Here's how you do that:
var a, name;
a = [];
a[0] = "zero";
a[10000] = "ten thousand";
for (name in a) {
// Only process this property name if it's a property of the
// instance itself (not its prototype), and if the name survives
// transition to and from a string unchanged -- e.g., it's numeric
if (a.hasOwnProperty(name) && parseInt(name) == name) {
alert(a[name]);
}
}
The above only alerts twice, "zero" and "ten thousand"; whereas a straight counting loop without the checks would alert 10,001 times (mostly saying "undefined" because it's looping through the gap).
The problem with the for ... in construct is that everything from the prototype(s) gets included in the enumeration.
What your output is showing is basically every attribute of images, which is an array object. So you get
all the elements in your array, i.e. the numbers that appear in your output.
all the properties available on your array. This is why you see length in your output for example.
Your code breaks due to number 2, since a functions does not have a style attribute
So, yes, as Pointy shows, the correct way to iterate over the elements of an array in JavaScript is by using a for loop.

Why is using "for...in" for array iteration a bad idea?

I've been told not to use for...in with arrays in JavaScript. Why not?
The reason is that one construct:
var a = []; // Create a new empty array.
a[5] = 5; // Perfectly legal JavaScript that resizes the array.
for (var i = 0; i < a.length; i++) {
// Iterate over numeric indexes from 0 to 5, as everyone expects.
console.log(a[i]);
}
/* Will display:
undefined
undefined
undefined
undefined
undefined
5
*/
can sometimes be totally different from the other:
var a = [];
a[5] = 5;
for (var x in a) {
// Shows only the explicitly set index of "5", and ignores 0-4
console.log(x);
}
/* Will display:
5
*/
Also consider that JavaScript libraries might do things like this, which will affect any array you create:
// Somewhere deep in your JavaScript library...
Array.prototype.foo = 1;
// Now you have no idea what the below code will do.
var a = [1, 2, 3, 4, 5];
for (var x in a){
// Now foo is a part of EVERY array and
// will show up here as a value of 'x'.
console.log(x);
}
/* Will display:
0
1
2
3
4
foo
*/
The for-in statement by itself is not a "bad practice", however it can be mis-used, for example, to iterate over arrays or array-like objects.
The purpose of the for-in statement is to enumerate over object properties. This statement will go up in the prototype chain, also enumerating over inherited properties, a thing that sometimes is not desired.
Also, the order of iteration is not guaranteed by the spec., meaning that if you want to "iterate" an array object, with this statement you cannot be sure that the properties (array indexes) will be visited in the numeric order.
For example, in JScript (IE <= 8), the order of enumeration even on Array objects is defined as the properties were created:
var array = [];
array[2] = 'c';
array[1] = 'b';
array[0] = 'a';
for (var p in array) {
//... p will be "2", "1" and "0" on IE
}
Also, speaking about inherited properties, if you, for example, extend the Array.prototype object (like some libraries as MooTools do), that properties will be also enumerated:
Array.prototype.last = function () { return this[this.length-1]; };
for (var p in []) { // an empty array
// last will be enumerated
}
As I said before to iterate over arrays or array-like objects, the best thing is to use a sequential loop, such as a plain-old for/while loop.
When you want to enumerate only the own properties of an object (the ones that aren't inherited), you can use the hasOwnProperty method:
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
// prop is not inherited
}
}
And some people even recommend calling the method directly from Object.prototype to avoid having problems if somebody adds a property named hasOwnProperty to our object:
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
// prop is not inherited
}
}
There are three reasons why you shouldn't use for..in to iterate over array elements:
for..in will loop over all own and inherited properties of the array object which aren't DontEnum; that means if someone adds properties to the specific array object (there are valid reasons for this - I've done so myself) or changed Array.prototype (which is considered bad practice in code which is supposed to work well with other scripts), these properties will be iterated over as well; inherited properties can be excluded by checking hasOwnProperty(), but that won't help you with properties set in the array object itself
for..in isn't guaranteed to preserve element ordering
it's slow because you have to walk all properties of the array object and its whole prototype chain and will still only get the property's name, ie to get the value, an additional lookup will be required
Because for...in enumerates through the object that holds the array, not the array itself. If I add a function to the arrays prototype chain, that will also be included. I.e.
Array.prototype.myOwnFunction = function() { alert(this); }
a = new Array();
a[0] = 'foo';
a[1] = 'bar';
for(x in a){
document.write(x + ' = ' + a[x]);
}
This will write:
0 = foo
1 = bar
myOwnFunction = function() { alert(this); }
And since you can never be sure that nothing will be added to the prototype chain just use a for loop to enumerate the array:
for(i=0,x=a.length;i<x;i++){
document.write(i + ' = ' + a[i]);
}
This will write:
0 = foo
1 = bar
As of 2016 (ES6) we may use for…of for array iteration, as John Slegers already noticed.
I would just like to add this simple demonstration code, to make things clearer:
Array.prototype.foo = 1;
var arr = [];
arr[5] = "xyz";
console.log("for...of:");
var count = 0;
for (var item of arr) {
console.log(count + ":", item);
count++;
}
console.log("for...in:");
count = 0;
for (var item in arr) {
console.log(count + ":", item);
count++;
}
The console shows:
for...of:
0: undefined
1: undefined
2: undefined
3: undefined
4: undefined
5: xyz
for...in:
0: 5
1: foo
In other words:
for...of counts from 0 to 5, and also ignores Array.prototype.foo. It shows array values.
for...in lists only the 5, ignoring undefined array indexes, but adding foo. It shows array property names.
Short answer: It's just not worth it.
Longer answer: It's just not worth it, even if sequential element order and optimal performance aren't required.
Long answer: It's just not worth it...
Using for (var property in array) will cause array to be iterated over as an object, traversing the object prototype chain and ultimately performing slower than an index-based for loop.
for (... in ...) is not guaranteed to return the object properties in sequential order, as one might expect.
Using hasOwnProperty() and !isNaN() checks to filter the object properties is an additional overhead causing it to perform even slower and negates the key reason for using it in the first place, i.e. because of the more concise format.
For these reasons an acceptable trade-off between performance and convenience doesn't even exist. There's really no benefit unless the intent is to handle the array as an object and perform operations on the object properties of the array.
In isolation, there is nothing wrong with using for-in on arrays. For-in iterates over the property names of an object, and in the case of an "out-of-the-box" array, the properties corresponds to the array indexes. (The built-in propertes like length, toString and so on are not included in the iteration.)
However, if your code (or the framework you are using) add custom properties to arrays or to the array prototype, then these properties will be included in the iteration, which is probably not what you want.
Some JS frameworks, like Prototype modifies the Array prototype. Other frameworks like JQuery doesn't, so with JQuery you can safely use for-in.
If you are in doubt, you probably shouldn't use for-in.
An alternative way of iterating through an array is using a for-loop:
for (var ix=0;ix<arr.length;ix++) alert(ix);
However, this have a different issue. The issue is that a JavaScript array can have "holes". If you define arr as:
var arr = ["hello"];
arr[100] = "goodbye";
Then the array have two items, but a length of 101. Using for-in will yield two indexes, while the for-loop will yield 101 indexes, where the 99 has a value of undefined.
In addition to the reasons given in other answers, you may not want to use the "for...in" structure if you need to do math with the counter variable because the loop iterates through the names of the object's properties and so the variable is a string.
For example,
for (var i=0; i<a.length; i++) {
document.write(i + ', ' + typeof i + ', ' + i+1);
}
will write
0, number, 1
1, number, 2
...
whereas,
for (var ii in a) {
document.write(i + ', ' + typeof i + ', ' + i+1);
}
will write
0, string, 01
1, string, 11
...
Of course, this can easily be overcome by including
ii = parseInt(ii);
in the loop, but the first structure is more direct.
Aside from the fact that for...in loops over all enumerable properties (which is not the same as "all array elements"!), see http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf, section 12.6.4 (5th edition) or 13.7.5.15 (7th edition):
The mechanics and order of enumerating the properties ... is not specified...
(Emphasis mine.)
That means if a browser wanted to, it could go through the properties in the order in which they were inserted. Or in numerical order. Or in lexical order (where "30" comes before "4"! Keep in mind all object keys -- and thus, all array indexes -- are actually strings, so that makes total sense). It could go through them by bucket, if it implemented objects as hash tables. Or take any of that and add "backwards". A browser could even iterate randomly and be ECMA-262 compliant, as long as it visited each property exactly once.
In practice, most browsers currently like to iterate in roughly the same order. But there's nothing saying they have to. That's implementation specific, and could change at any time if another way was found to be far more efficient.
Either way, for...in carries with it no connotation of order. If you care about order, be explicit about it and use a regular for loop with an index.
Mainly two reasons:
One
Like others have said, You might get keys which aren't in your array or that are inherited from the prototype. So if, let's say, a library adds a property to the Array or Object prototypes:
Array.prototype.someProperty = true
You'll get it as part of every array:
for(var item in [1,2,3]){
console.log(item) // will log 1,2,3 but also "someProperty"
}
you could solve this with the hasOwnProperty method:
var ary = [1,2,3];
for(var item in ary){
if(ary.hasOwnProperty(item)){
console.log(item) // will log only 1,2,3
}
}
but this is true for iterating over any object with a for-in loop.
Two
Usually the order of the items in an array is important, but the for-in loop won't necessarily iterate in the right order, that's because it treats the array as an object, which is the way it is implemented in JS, and not as an array.
This seems like a small thing, but it can really screw up applications and is hard to debug.
I don't think I have much to add to eg. Triptych's answer or CMS's answer on why using for...in should be avoided in some cases.
I do, however, would like to add that in modern browsers there is an alternative to for...in that can be used in those cases where for...in can't be used. That alternative is for...of :
for (var item of items) {
console.log(item);
}
Note :
Unfortunately, no version of Internet Explorer supports for...of (Edge 12+ does), so you'll have to wait a bit longer until you can use it in your client side production code. However, it should be safe to use in your server side JS code (if you use Node.js).
Because it enumerates through object fields, not indexes. You can get value with index "length" and I doubt you want this.
The problem with for ... in ... — and this only becomes a problem when a programmer doesn't really understand the language; it's not really a bug or anything — is that it iterates over all members of an object (well, all enumerable members, but that's a detail for now). When you want to iterate over just the indexed properties of an array, the only guaranteed way to keep things semantically consistent is to use an integer index (that is, a for (var i = 0; i < array.length; ++i) style loop).
Any object can have arbitrary properties associated with it. There would be nothing terrible about loading additional properties onto an array instance, in particular. Code that wants to see only indexed array-like properties therefore must stick to an integer index. Code that is fully aware of what for ... in does and really need to see all properties, well then that's ok too.
TL&DR: Using the for in loop in arrays is not evil, in fact quite the opposite.
I think the for in loop is a gem of JS if used correctly in arrays. You are expected to have full control over your software and know what you are doing. Let's see the mentioned drawbacks and disprove them one by one.
It loops through inherited properties as well: First of all any extensions to the Array.prototype should have been done by using Object.defineProperty() and their enumerable descriptor should be set to false. Any library not doing so should not be used at all.
Properties those you add to the inheritance chain later get counted: When doing array sub-classing by Object.setPrototypeOf or by Class extend. You should again use Object.defineProperty() which by default sets the writable, enumerable and configurable property descriptors to false. Lets see an array sub-classing example here...
function Stack(...a){
var stack = new Array(...a);
Object.setPrototypeOf(stack, Stack.prototype);
return stack;
}
Stack.prototype = Object.create(Array.prototype); // now stack has full access to array methods.
Object.defineProperty(Stack.prototype,"constructor",{value:Stack}); // now Stack is a proper constructor
Object.defineProperty(Stack.prototype,"peak",{value: function(){ // add Stack "only" methods to the Stack.prototype.
return this[this.length-1];
}
});
var s = new Stack(1,2,3,4,1);
console.log(s.peak());
s[s.length] = 7;
console.log("length:",s.length);
s.push(42);
console.log(JSON.stringify(s));
console.log("length:",s.length);
for(var i in s) console.log(s[i]);
So you see.. for in loop is now safe since you cared about your code.
The for in loop is slow: Hell no. It's by far the fastest method of iteration if you are looping over sparse arrays which are needed time to time. This is one of the most important performance tricks that one should know. Let's see an example. We will loop over a sparse array.
var a = [];
a[0] = "zero";
a[10000000] = "ten million";
console.time("for loop on array a:");
for(var i=0; i < a.length; i++) a[i] && console.log(a[i]);
console.timeEnd("for loop on array a:");
console.time("for in loop on array a:");
for(var i in a) a[i] && console.log(a[i]);
console.timeEnd("for in loop on array a:");
Also, due to semantics, the way for, in treats arrays (i.e. the same as any other JavaScript object) is not aligned with other popular languages.
// C#
char[] a = new char[] {'A', 'B', 'C'};
foreach (char x in a) System.Console.Write(x); //Output: "ABC"
// Java
char[] a = {'A', 'B', 'C'};
for (char x : a) System.out.print(x); //Output: "ABC"
// PHP
$a = array('A', 'B', 'C');
foreach ($a as $x) echo $x; //Output: "ABC"
// JavaScript
var a = ['A', 'B', 'C'];
for (var x in a) document.write(x); //Output: "012"
Here are the reasons why this is (usually) a bad practice:
for...in loops iterate over all their own enumerable properties and the enumerable properties of their prototype(s). Usually in an array iteration we only want to iterate over the array itself. And even though you yourself may not add anything to the array, your libraries or framework might add something.
Example:
Array.prototype.hithere = 'hithere';
var array = [1, 2, 3];
for (let el in array){
// the hithere property will also be iterated over
console.log(el);
}
for...in loops do not guarantee a specific iteration order. Although is order is usually seen in most modern browsers these days, there is still no 100% guarantee.
for...in loops ignore undefined array elements, i.e. array elements which not have been assigned yet.
Example::
const arr = [];
arr[3] = 'foo'; // resize the array to 4
arr[4] = undefined; // add another element with value undefined to it
// iterate over the array, a for loop does show the undefined elements
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
console.log('\n');
// for in does ignore the undefined elements
for (let el in arr) {
console.log(arr[el]);
}
In addition to the other problems, the "for..in" syntax is probably slower, because the index is a string, not an integer.
var a = ["a"]
for (var i in a)
alert(typeof i) // 'string'
for (var i = 0; i < a.length; i++)
alert(typeof i) // 'number'
An important aspect is that for...in only iterates over properties contained in an object which have their enumerable property attribute set to true. So if one attempts to iterate over an object using for...in then arbitrary properties may be missed if their enumerable property attribute is false. It is quite possible to alter the enumerable property attribute for normal Array objects so that certain elements are not enumerated. Though in general the property attributes tend to apply to function properties within an object.
One can check the value of a properties' enumerable property attribute by:
myobject.propertyIsEnumerable('myproperty')
Or to obtain all four property attributes:
Object.getOwnPropertyDescriptor(myobject,'myproperty')
This is a feature available in ECMAScript 5 - in earlier versions it was not possible to alter the value of the enumerable property attribute (it was always set to true).
The for/in works with two types of variables: hashtables (associative arrays) and array (non-associative).
JavaScript will automatically determine the way its passes through the items. So if you know that your array is really non-associative you can use for (var i=0; i<=arrayLen; i++), and skip the auto-detection iteration.
But in my opinion, it's better to use for/in, the process required for that auto-detection is very small.
A real answer for this will depend on how the browser parsers/interpret the JavaScript code. It can change between browsers.
I can't think of other purposes to not using for/in;
//Non-associative
var arr = ['a', 'b', 'c'];
for (var i in arr)
alert(arr[i]);
//Associative
var arr = {
item1 : 'a',
item2 : 'b',
item3 : 'c'
};
for (var i in arr)
alert(arr[i]);
Because it will iterate over properties belonging to objects up the prototype chain if you're not careful.
You can use for.. in, just be sure to check each property with hasOwnProperty.
It's not necessarily bad (based on what you're doing), but in the case of arrays, if something has been added to Array.prototype, then you're going to get strange results. Where you'd expect this loop to run three times:
var arr = ['a','b','c'];
for (var key in arr) { ... }
If a function called helpfulUtilityMethod has been added to Array's prototype, then your loop would end up running four times: key would be 0, 1, 2, and helpfulUtilityMethod. If you were only expecting integers, oops.
You should use the for(var x in y) only on property lists, not on objects (as explained above).
Using the for...in loop for an array is not wrong, although I can guess why someone told you that:
1.) There is already a higher order function, or method, that has that purpose for an array, but has more functionality and leaner syntax, called 'forEach': Array.prototype.forEach(function(element, index, array) {} );
2.) Arrays always have a length, but for...in and forEach do not execute a function for any value that is 'undefined', only for the indexes that have a value defined. So if you only assign one value, these loops will only execute a function once, but since an array is enumerated, it will always have a length up to the highest index that has a defined value, but that length could go unnoticed when using these loops.
3.) The standard for loop will execute a function as many times as you define in the parameters, and since an array is numbered, it makes more sense to define how many times you want to execute a function. Unlike the other loops, the for loop can then execute a function for every index in the array, whether the value is defined or not.
In essence, you can use any loop, but you should remember exactly how they work. Understand the conditions upon which the different loops reiterate, their separate functionalities, and realize they will be more or less appropriate for differing scenarios.
Also, it may be considered a better practice to use the forEach method than the for...in loop in general, because it is easier to write and has more functionality, so you may want to get in the habit of only using this method and standard for, but your call.
See below that the first two loops only execute the console.log statements once, while the standard for loop executes the function as many times as specified, in this case, array.length = 6.
var arr = [];
arr[5] = 'F';
for (var index in arr) {
console.log(index);
console.log(arr[index]);
console.log(arr)
}
// 5
// 'F'
// => (6) [undefined x 5, 6]
arr.forEach(function(element, index, arr) {
console.log(index);
console.log(element);
console.log(arr);
});
// 5
// 'F'
// => Array (6) [undefined x 5, 6]
for (var index = 0; index < arr.length; index++) {
console.log(index);
console.log(arr[index]);
console.log(arr);
};
// 0
// undefined
// => Array (6) [undefined x 5, 6]
// 1
// undefined
// => Array (6) [undefined x 5, 6]
// 2
// undefined
// => Array (6) [undefined x 5, 6]
// 3
// undefined
// => Array (6) [undefined x 5, 6]
// 4
// undefined
// => Array (6) [undefined x 5, 6]
// 5
// 'F'
// => Array (6) [undefined x 5, 6]
A for...in loop always enumerates the keys.
Objects properties keys are always String, even the indexed properties of an array :
var myArray = ['a', 'b', 'c', 'd'];
var total = 0
for (elem in myArray) {
total += elem
}
console.log(total); // 00123
for...in is useful when working on an object in JavaScript, but not for an Array, but still we can not say it's a wrong way, but it's not recommended, look at this example below using for...in loop:
let txt = "";
const person = {fname:"Alireza", lname:"Dezfoolian", age:35};
for (const x in person) {
txt += person[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35
OK, let's do it with Array now:
let txt = "";
const person = ["Alireza", "Dezfoolian", 35];
for (const x in person) {
txt += person[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35
As you see the result the same...
But let's try something, let's prototype something to Array...
Array.prototype.someoneelse = "someoneelse";
Now we create a new Array();
let txt = "";
const arr = new Array();
arr[0] = 'Alireza';
arr[1] = 'Dezfoolian';
arr[2] = 35;
for(x in arr) {
txt += arr[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35 someoneelse
You see the someoneelse!!!... We actually looping through new Array object in this case!
So that's one of the reasons why we need to use for..in carefully, but it's not always the case...
Since JavaScript elements are saved as standard object properties, it
is not advisable to iterate through JavaScript arrays using for...in
loops because normal elements and all enumerable properties will be
listed.
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections
although not specifically addressed by this question, I would add that there's a very good reason not to ever use for...in with a NodeList (as one would obtain from a querySelectorAll call, as it doesn't see the returned elements at all, instead iterating only over the NodeList properties.
in the case of a single result, I got:
var nodes = document.querySelectorAll(selector);
nodes
▶ NodeList [a._19eb]
for (node in nodes) {console.log(node)};
VM505:1 0
VM505:1 length
VM505:1 item
VM505:1 entries
VM505:1 forEach
VM505:1 keys
VM505:1 values
which explained why my for (node in nodes) node.href = newLink; was failing.
for in loop converts the indices to string when traversing through an array.
For example, In the below code, in the second loop where initialising j with i+1, i is the index but in a string ("0", "1" etc) and number + string in js is a string. if js encounters "0" + 1 it will return "01".
var maxProfit = function(prices) {
let maxProfit = 0;
for (let i in prices) {
for (let j = i + 1; j < prices.length; j++) {
console.log(prices[j] - prices[i], "i,j", i, j, typeof i, typeof j);
if ((prices[j] - prices[i]) > maxProfit) maxProfit = (prices[j] - prices[i]);
}
}
return maxProfit;
};
maxProfit([7, 1, 5, 3, 6, 4]);

Categories