var xs=[]; for (var i in [1,2,3]) xs.push(i); console.log(xs);
Why ["0", "1", "2"] and not [0, 1, 2]?
I have the hunch that this is due to array internal implementation.
Array in javascript may be seen as {"0":1, "1":2, "2":3}?
EDIT: I write a compiler. I don't care that I don't need to use for in and arrays. I don't care about readability of the line. I'd like to know why the keys of the array object are strings and not numbers. Any statements from specification would be appreciated.
Don't loop with in on an array.
Loop with of :
var xs=[];
for (var i of [1,2,3]) xs.push(i);
console.log(xs);
Basically, in loops on object keys, and of loops on array value. The "0" "1" and "2" are keys.
The problem:
for...in loop is not meant to iterate over an array, but was designed to enumerate the object keys. Per the docs on MDN:
for...in should not be used to iterate over an Array where the index order is important.
If used with the arrays, the loop treats the array like an object, and considers the indices as the keys (so the stringified keys are printed).
The quick fix:
The problem with you code is that the statement for (var i in [1,2,3]) yields the array indices as i in the loop body. You may try a simple fix in the loop body:
var xs=[]; for (var i in [1,2,3]) xs.push([1,2,3][i]); console.log(xs);
You may want to extract [1,2,3] in a variable to get the code more readable.
The recommended fix:
Use Array#forEach instead. It is specifically designed to loop over arrays, and is stable across all environments.
var xs=[]; [1,2,3].forEach(item => xs.push(item)); console.log(xs);
Related
I saw this for the first time (or noticed it for the first time) today during a maintenance of a colleagues code.
Essentially the "weird" part is the same as if you try to run this code:
var arr = [];
arr[0] = "cat"; // this adds to the array
arr[1] = "mouse"; // this adds to the array
arr.length; // returns 2
arr["favoriteFood"] = "pizza"; // this DOES NOT add to the array. Setting a string parameter adds to the underlying object
arr.length; // returns 2, not 3
Got this example from nfiredly.com
I don't know what the technical term for this "case" is so I haven't been able to find any additional information about it here or on Google but it strikes me very peculiar that this "behaviour" can at all exists in JavaScript; a kind of "mix" between Arrays and Objects (or Associative Arrays).
It states in the above code snippet that that Setting a string parameter adds to the underlying object and thus not affect the length of the "array" itself.
What is this kind of pattern?
Why is it at all possible? Is it a weird JS quirk or is it deliberate?
For what purpose would you "mix" these types?
It's possible because arrays are objects with some special behaviors, but objects nevertheless.
15.4 Array Objects
However, if you start using non-array properties on an array, some implementations may change the underlying data structure to a hash. Then array operations might be slower.
In JavaScript, arrays, functions and objects are all objects. Arrays are objects created with Array constructor function.
E.g.
var a = new Array();
Or, using shortcut array literal,
var a = [];
Both are the same. They both create objects. However, special kind of object. It has a length property and numeric properties with corresponding values which are the array elements.
This object (array) has methods like push, pop etc. which you can use to manipulate the object.
When you add a non-numeric property to this array object, you do not affect its length. But, you do add a new property to the object.
So, if you have
var a = [1];
a.x = 'y';
console.log(Object.keys(a)); // outputs ["0", "x"]
console.log(a); // outputs [1];
I have an array var test = [1, 2, 3]. When using for in method to go through the array something wrong happened. Please see the snippet here:
var test = [1, 2, 3]
for (var i in test) {
alert(i);
}
It will alert "0", "1" and "2" here in the snippet. But in my computer, it will alert "0", "1", "2" and an "equal". I think equal is a method of the array object itself.
This behavior didn't appear a week ago, thus my previous code which was written using for in is strongly affected.
Can anyone suggest what causes this strange behavior? And how may I avoid this behavior without changing my code?
This is because some library you're using (or maybe even something you wrote yourself) does this:
Array.prototype.equals = function() { ... }
This is the downside of the in operator - it enumerates the extra properties too. You can use the hasOwnProperty() method to check i and ignore the properties that are not set on the object. Or, for arrays, use this instead:
for (var i = 0; i < test.length; i++ )
Of course, this only works on continuous arrays that start at 0.
for (var i in test) enumerates all properties of the test array (remember an Array is an Object and can have arbitrary non-numeric properties too). This includes not only the indexes of the array, but also any enumerable properties that someone else might have added to the Array object. This is generally considered the wrong way to enumerate an array. This structure is made to enumerate all properties of an object, not only the array indexes of an array.
Instead, you can use any of these:
for (var i = 0; i < test.length; i++)
test.forEach(fn);
test.every(fn);
test.some(fn);
These will only enumerate actual array items, not other properties added to the array.
On sparse arrays (where not all items have been initialized), the for loop will visit every item (even the uninitialized items), whereas the others will skip the uninitialized items.
The fact that you are seeing the equal property show up in your enumeration means that someone has added an enumerable property to the Array object and thus it shows up with the for (var i in test) form of enumeration.
In ES6, you can also use the of iteration technique and this will be safe from the non-array element properties and will return the same items that .forEach() will return. Note, it also differs from in because it delivers the actual array values, not the array indexes:
var test = [4, 7, 13];
test.whatever = "foo";
for (var item of test) {
console.log(item); // 4, 7, 13
}
How is regex stored in javascript. Is not stored like the usual way other var types like string is stored.
var regexOne = /^(regex).*$/gm;
var regexTwo = /^(regex).*$/gm;
var regexThree = /^(regex).*$/gm;
var regexFour = /^(regex).*$/gm;
var searchQuery = [regexOne, regexTwo, regexThree, regexFour];
for(query in searchQuery){
console.dir(query.toString());
}
The above code prints:
'0'
'1'
'2'
'3'
How can i get this working.
When you iterate an Array with for..in loop, the loop variable with have just the current index as string, not the actual value. Quoting MDN documentation on Array iteration and for...in,
The for..in statement iterates over the enumerable properties of an object, in arbitrary order.
....
....
Note: for..in should not be used to iterate over an Array where index order is important.
Array indexes are just enumerable properties with integer names and are otherwise identical to general Object properties. There is no guarantee that for...in will return the indexes in any particular order and it will return all enumerable properties, including those with non–integer names and those that are inherited.
Because the order of iteration is implementation dependent, iterating over an array may not visit elements in a consistent order. Therefore it is better to use a for loop with a numeric index (or Array.forEach or the for...of loop) when iterating over arrays where the order of access is important.
The bold text above says it all. So, you should iterate arrays with one of the following options
normal for loop
for(var i = 0; i < searchQuery.length; i += 1) {
console.dir(searchQuery[i]);
}
Array.prototype.forEach function
searchQuery.forEach(function(currentRegEx) {
console.dir(currentRegEx);
});
for...of, loop (Note: This will work only in environments which implement ECMAScript 6)
for(var currentRegEx of searchQuery) {
console.dir(currentRegEx);
}
for-in, in JavaScript, loops through the enumerable property names of an object. It's not for looping through array entries or array indexes (although with safeguards it can be used for the latter, which is why you're seeing 0, 1, etc. — those property names are array indexes).
For details about looping through arrays, see this answer, which has a thorough list of options and explanations of each of them.
Side note 1:
Your code is falling prey to The Horror of Implicit Globals because you never declare the query variable. (The for-in construct doesn't declare it for you.)
Side note 2:
Unless you need the regexOne and such variables, you can create your array of regexes more concisely:
var searchQuery = [
/^(regex).*$/gm,
/^(regex).*$/gm,
/^(regex).*$/gm,
/^(regex).*$/gm
];
I was working on a small javascript coding challenge that was simple enough, but ran into a odd bit of strange behavior that I couldn't find documented anywhere. Maybe someone could point me to where it states that this is expected behavior?
myIntegerArray = [1,2,3,4];
b = new Array();
for(var v in a)
{
b.push(v);
}
console.log(b); // returns ["1","2","3","4"]. Note String result
If I were to use the forEach() however I get an array of Numbers back:
a.forEach(function(element,index,ay)
{
b.push(element)
});
//a console.log(b) will return [1,2,3,4]
You're pushing the key name, not the value. You need to to do this:
b.push(a[v]);
This might help you understand:
for (var key in obj) {
var value = obj[key];
arr.push(value);
}
for(var v in a)
In JavaScript, Arrays are just like Objects. for..in loop will get the keys of the Array objects, which are the actual array indices. As we know that, JavaScript Object keys can only be Strings. So, what you are actually getting is, the Array indices in String format.
And another reason why for..in should not be used, is in MDN docs. Quoting from for..in
for..in should not be used to iterate over an Array where index order
is important. Array indexes are just enumerable properties with
integer names and are otherwise identical to general Object
properties. There is no guarantee that for...in will return the
indexes in any particular order and it will return all enumerable
properties, including those with non–integer names and those that are
inherited.
Because the order of iteration is implementation dependent, iterating
over an array may not visit elements in a consistent order. Therefore
it is better to use a for loop with a numeric index (or Array.forEach
or the non-standard for...of loop) when iterating over arrays where
the order of access is important.
So, you either use
for(var index = 0; index < array.length; index += 1) {
array[index];
}
Or the forEach which you have shown in the question itself.
var myArr = [{a:1, b:2}, {c:3, d:4}];
for (var item in myArr) {
console.log(item);
}
Item returns the key (ex: 0, 1) instead of the object itself. Why?
Douglas Crockford recommends in JavaScript: The Good Parts to avoid using the for in statement.
If you use for in to loop over property names in an object, the results are not ordered.
The for in loop is best for iterating over name-value pairs, and the for each loop best for iterating over values i.e arrays.
E.g,
var o = {'name':'Batman', 'age':33, 'city':'Gotham City'};
for (var p in o) {
console.log(p+': '+o[p]);
}
There’s no way we can get the property name if we were to use the For Each Loop for the above object.
Note :
The For in Loop is best for name-value pairs.
The For Each Loop is best for iterable values. Eg: arrays, and objects if you are not interested in the name of the property.
Javascript for..in loops always return the index/name, not the value. To get what you want, you should use:
var myArr = [{a:1, b:2}, {c:3, d:4}];
for (var index in myArr) {
console.log( myArr[index] );
}
However, as said before, the for..in statement should be use with caution, and it is not intended to be used with an array. You should use a for loop instead
var myArr = [{a:1, b:2}, {c:3, d:4}];
for( var i=0, l=myArr.length; i<l; i++ ) {
console.log( myArr[i] );
}
The for ... in loop iterates over the keys (properties) of an object.
It is not intended to be used for arrays.
It will also iterate over properties inherited from the object's prototype.
Adding an answer here to accommodate the latest ECMAScript 6 standard.
Check out this page for a great read with examples.
And a rather tasty caveat: this awesome new functionality will work with nearly ever iterable object! From MDN:
The for...of statement creates a loop iterating over iterable objects
(including Array, Map, Set, String, TypedArray, arguments object and
so on)...
So for example, you could use:
for (let item of myArr) {
console.log(item);
}
Although to super clear that you are logging an object, I would be a bit nicer to the next person to read your code by renaming "item" to "obj", producing this:
for (let obj of myArr) {
console.log(obj);
}
Why rename the variable? Well, although we use the term 'item' to denote any generic item in an array, your array only contains objects. If you know, or expect, this array to only every contain objects, you could name the variable based on the type of item (i.e. an object) the array contains.
Happy coding!