I'd like to ask a question about JavaScript arrays.
Does the array behave like an object when we use for..in loop to iterate. I mean in this case can indexes take the role of properties(keys).
While you can do for..in syntax on an array, you shouldn't because you will will iterate over any properties you may have assigned to the array.
Example:
var array = [0, 1];
array.three = 2;
for (var p in array){
console.log(array[p]); //print 0, 1, 2
}
for(var i = 0; i < array.length; i++){
console.log(array[i]); //prints 0, 1
}
So, when dealing with arrays you should always use the for var i approach to avoid running into unexpected behavior.
As everything in JS, an array is an object.
It means you can use an array as a prototype :
var obj = Object.create([]);
console.log(obj instanceof Array); // true
obj[0] = "value 1";
obj.test = "value of property test";
for(var i in obj) console.log(obj[i]); // "value 1" "value of property test"
or any other thing you would do with an object, including using a for ... in loop.
However, the length property is updated with the highest (integer) index of the array +1.
var arr = ["one","two"];
arr.length; // 2
That's why it's preferred not to use for ... in loops when you only want to iterate on the values of the array : you can use for(var i=0,var l=arr.length;i<arr.length;i++) instead.
Yes ,you can access array like an object Only if array keys are string,
var sdf = [];
sdf['asd'] =45;
sdf[32] =8674;
console.log(sdf.asd) // WORKS
console.log(sdf.32) // Error
Array.prototype.forEach is what you want. Just be mindful of browser support or use a framework that corrects for unsupported browsers: http://kangax.github.io/compat-table/es5/#Array.prototype.forEach
for in should be used for iterating over object properties because order is not guaranteed.
Related
I just want to know why forEach doesn't work on an associative array:
var array =[];
array['W'] = 0;
array['S'] = 1;
// This doesn't work
console.log(array);
array.forEach(function(item){
console.log(item);
});
// This does
for(var key in array){
console.log(array[key]);
}
Array.prototype.forEach is defined by the standard to iterate over index members.
for-in enumerates all object properties.
So in short, the answer to your "why" question is: because the standard says so.
Probably because array.length evaluates to 0. You could use Object.values(array).forEach to iterate over the actual values of the array.
I have the following JavaScript code fragment
var ip = new Array();
// This array filled with values and passed to function
function calculateTime(ip) {
for (i in ip) {
window.alert(i);
if (!i in myArray) {
myArray[i] = 0;
} else {
myArray[i] += 1;
}
}
}
I expect i to be an index (0, 1, 2 ...) but sometimes window.alert prints "arrayIndex" and because of that my code doesn't work correctly. Can someone explain me the reason? I am new in JavaScript.
for in will loop over all the enumerable properties of an object.
None of the properties that come with an array are enumerable in modern browsers, but any that are added (such as the normal array indexes or any custom named properties) will be.
Somewhere you have some code that is adding an arrayIndex property to your array and it is coming up when you loop over it.
var myArray = [];
myArray[0] = 1;
myArray[1] = 1;
myArray[2] = 1;
myArray.arrayIndex = 1;
for (prop in myArray) {
console.log(prop);
}
If you only want to get numerical indexes, then use a standard for loop.
for (var i = 0 ; i < myArray.length ; i++) {
console.log(i);
}
For arrays, you should use a numeric variable rather than in:
for(var i = 0; i < ip.length; i++)
in is to iterate over the keys of an Object, but even there you have to take much care to filter out inherited properties.
Now, since arrays are objects too in JavaScript, you can assign them object properties:
ip["arrayIndex"] = 'some value';
Then "arrayIndex" will show up in a for...in iteration, whereas in a "normal" for loop, it won't.
Use either
for(var i=0; i<ip.length; i++){
//your code
}
or
ip.forEach(function(val,i){
// your code
});
The for(var x in y) loop works best for Object rather than Array. When you use it on arrays it will loop through all properties including named ones like length not just numerical indices.
I want to find out how many items are in my JSON object. I have seen many answers but they all deal with a common value to loop through. I am wanting the results to tell me that there are 2 items in this object. Any help would be great!
[{"manager_first_name":"jim","manager_last_name":"gaffigan"}]
You could use Object.keys in newer browsers. It would return an array of all the keys in the object, and that array would have a length property that will tell you how many items there are in the object :
var arr = [{"manager_first_name":"jim","manager_last_name":"gaffigan"}];
var length = Object.keys(arr[0]).length;
FIDDLE
In non-supporting browsers, you have to iterate
var arr = [{"manager_first_name":"jim","manager_last_name":"gaffigan"}];
var i = 0;
for (var key in arr[0]) i++;
FIDDLE
You can do this:
var arr = [{"manager_first_name":"jim","manager_last_name":"gaffigan"}],
length = 0,
obj = arr[0]; // Get first obj from array
for(var k in obj){
if( obj.hasOwnProperty(k) ) {
length++;
}
}
console.log(length); // Shows 2
You should use hasOwnProperty because you can also extend an Object with functions, there could otherwise also be count als keys.
Links:
hasOwnProperty
Try
var jsonArr = [{"manager_first_name":"jim","manager_last_name":"gaffigan"}];
var itemCount = JSON.stringify(jsonArr).split('":"').length - 1;
This is, of course, a rather coarse(and unreliable) way of doing it, but if you just want the item count, this should work like a charm.
Why is my for for-each loop not iterating over my JavaScript associative array object?
// Defining an array
var array = [];
// Assigning values to corresponding keys
array["Main"] = "Main page";
array["Guide"] = "Guide page";
array["Articles"] = "Articles page";
array["Forum"] = "Forum board";
// Expected: loop over every item,
// yet it logs only "last" assigned value - "Forum"
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
jQuery each() could be helpful: https://api.jquery.com/jQuery.each/
The .length property only tracks properties with numeric indexes (keys). You're using strings for keys.
You can do this:
var arr_jq_TabContents = {}; // no need for an array
arr_jq_TabContents["Main"] = jq_TabContents_Main;
arr_jq_TabContents["Guide"] = jq_TabContents_Guide;
arr_jq_TabContents["Articles"] = jq_TabContents_Articles;
arr_jq_TabContents["Forum"] = jq_TabContents_Forum;
for (var key in arr_jq_TabContents) {
console.log(arr_jq_TabContents[key]);
}
To be safe, it's a good idea in loops like that to make sure that none of the properties are unexpected results of inheritance:
for (var key in arr_jq_TabContents) {
if (arr_jq_TabContents.hasOwnProperty(key))
console.log(arr_jq_TabContents[key]);
}
edit — it's probably a good idea now to note that the Object.keys() function is available on modern browsers and in Node etc. That function returns the "own" keys of an object, as an array:
Object.keys(arr_jq_TabContents).forEach(function(key, index) {
console.log(this[key]);
}, arr_jq_TabContents);
The callback function passed to .forEach() is called with each key and the key's index in the array returned by Object.keys(). It's also passed the array through which the function is iterating, but that array is not really useful to us; we need the original object. That can be accessed directly by name, but (in my opinion) it's a little nicer to pass it explicitly, which is done by passing a second argument to .forEach() — the original object — which will be bound as this inside the callback. (Just saw that this was noted in a comment below.)
This is very simple approach. The advantage is you can get keys as well:
for (var key in array) {
var value = array[key];
console.log(key, value);
}
For ES6:
array.forEach(value => {
console.log(value)
})
For ES6 (if you want the value, index and the array itself):
array.forEach((value, index, self) => {
console.log(value, index, self)
})
If Node.js or the browser support Object.entries(), it can be used as an alternative to using Object.keys() (Pointy's answer).
const h = {
a: 1,
b: 2
};
Object.entries(h).forEach(([key, value]) => console.log(value));
// logs 1, 2
In this example, forEach uses destructuring assignment of an array.
There are some straightforward examples already, but I notice from how you've worded your question that you probably come from a PHP background, and you're expecting JavaScript to work the same way -- it does not. A PHP array is very different from a JavaScript Array.
In PHP, an associative array can do most of what a numerically-indexed array can (the array_* functions work, you can count() it, etc.). You simply create an array and start assigning to string indexes instead of numeric.
In JavaScript, everything is an object (except for primitives: string, numeric, boolean), and arrays are a certain implementation that lets you have numeric indexes. Anything pushed to an array will affect its length, and can be iterated over using Array methods (map, forEach, reduce, filter, find, etc.) However, because everything is an object, you're always free to simply assign properties, because that's something you do to any object. Square-bracket notation is simply another way to access a property, so in your case:
array['Main'] = 'Main Page';
is actually equivalent to:
array.Main = 'Main Page';
From your description, my guess is that you want an 'associative array', but for JavaScript, this is a simple case of using an object as a hashmap. Also, I know it's an example, but avoid non-meaningful names that only describe the variable type (e.g. array), and name based on what it should contain (e.g. pages). Simple objects don't have many good direct ways to iterate, so often we'll turn then into arrays first using Object methods (Object.keys in this case -- there's also entries and values being added to some browsers right now) which we can loop.
// Assigning values to corresponding keys
const pages = {
Main: 'Main page',
Guide: 'Guide page',
Articles: 'Articles page',
Forum: 'Forum board',
};
Object.keys(pages).forEach((page) => console.log(page));
arr_jq_TabContents[key] sees the array as an 0-index form.
Here is a simple way to use an associative array as a generic Object type:
Object.prototype.forEach = function(cb){
if(this instanceof Array) return this.forEach(cb);
let self = this;
Object.getOwnPropertyNames(this).forEach(
(k)=>{ cb.call(self, self[k], k); }
);
};
Object({a:1,b:2,c:3}).forEach((value, key)=>{
console.log(`key/value pair: ${key}/${value}`);
});
This is (essentially) incorrect in most cases:
var array = [];
array["Main"] = "Main page";
That creates a non-element property on the array with the name Main. Although arrays are objects, normally you don't want to create non-element properties on them.
If you want to index into array by those names, typically you'd use a Map or a plain object, not an array.
With a Map (ES2015+), which I'll call map because I'm creative:
let map = new Map();
map.set("Main", "Main page");
you then iterate it using the iterators from its values, keys, or entries methods, for instance:
for (const value of map.values()) {
// Here, `value` will be `"Main page"`, etc.
}
Using a plain object, which I'll creatively call obj:
let obj = Object.create(null); // Creates an object with no prototype
obj.Main = "Main page"; // Or: `obj["Main"] = "Main page";`
you'd then iterate its contents using Object.keys, Object.values, or Object.entries, for instance:
for (const value of Object.values(proches_X)) {
// Here, `value` will be `"Main page"`, etc.
}
var obj = {
no: ["no", 32],
nt: ["no", 32],
nf: ["no", 32, 90]
};
count = -1; // Which must be a static value
for (i in obj) {
count++;
if (obj.hasOwnProperty(i)) {
console.log(obj[i][count])
};
};
In this code I used the brackets method for call values in an array because it contained an array. However, briefly the idea which a variable i has a key of property and with a loop called both values of the associative array.
It is the perfect method.
You can do this:
var array = [];
// Assigning values to corresponding keys
array[0] = "Main page";
array[1] = "Guide page";
array[2] = "Articles page";
array[3] = "Forum board";
array.forEach(value => {
console.log(value)
})
It seems like almost every answer is not what was asked at the very first place.
It's seems bit off that foreach-loop does not work. and simple for-loop will not work as well because length property will be zero in case of associative arrays(one of the fallback). but for-in do the thing for associative array
// Defining an array
var array = [];
// Assigning values to corresponding keys
array["Main"] = "Main page";
array["Guide"] = "Guide page";
array["Articles"] = "Articles page";
array["Forum"] = "Forum board";
// Expected: loop over every item,
// yet it logs only "last" assigned value - "Forum"
for (var index in array) {
console.log(index,array[index]);
}
I need to iterate over an array for which the keys are non-consecutive:
var messages = new Array();
messages[0] = "This is the first message";
messages[3] = "This is another message";
Obviously using the index of a for loop will not work as it depends on the keys being sequential:
for (var i=0 ; i<messages.length ; i++) {
alert(messages[i]); // Will only alert the first message, as i is never equal to 3
}
What is the canonical way of dealing with this, seeing as the for-each syntax is not intended for iterating over values in an array in javascript? Thanks.
The idiomatic way would be to use an object, not an array. Just be sure to check hasOwnProperty to make sure you don't pick up stray things which may have been added to the prototype.
var messages = { };
messages[0] = "This is the first message";
messages[3] = "This is another message";
for (var i in messages) {
if (messages.hasOwnProperty(i))
alert(messages[i]);
}
Or, the more modern way would be to use Object.keys
Object.keys(messages).forEach(prop => {
alert(messages[prop]);
});
Be sure to transpile that code with Babel if you plan on running it in older browsers like IE.
for(var i in messages)
{
console.log(messages[i]);
}
You could ignore the undefined properties...
for (var i=0 ; i<messages.length ; i++) {
if(messages[i] !== undefined)
alert(messages[i]);
}
Or use forEach, which will ignore undefined undeclared properties...
messages.forEach(function(v,i) {
alert(v);
});
Simple! if the array has regular gaps between the indices do this:
for (var i = 0 ; i < messages.length; i += gap) {
alert(messages[i]); // Will only alert the messages at the regular interval/gap
}
You can use each() jQuery method to do this.
$.each(messages, function(index, val){
alert(val);
});
From jQuery docs
each()
A generic iterator function, which can be used to seamlessly iterate
over both objects and arrays. Arrays and array-like objects with a
length property (such as a function's arguments object) are iterated
by numeric index, from 0 to length-1. Other objects are iterated via
their named properties.
When you create an array and give it values at 0 and 3, undefined values are created at 1 and 2. try this:
$.each(messages, function(i,val) {
if (val) {
alert(val);
}
});
For a use case such with the assumptions:
array.length >== 1
(i.e: an array with meaningful data in it already)
Where you are interested in the data from array[1], array[15], array[45] etc
You can do something similar to:
var array = ["you","will","become","strong","with","the","codes","padawan"];
var values = [1,5,7];
for (var i = 0; i < values.length; i++){
var cypher = values[i];
console.log(array[cypher]);
}
//will, the, padawan
Or perhaps something more meaningful such as:
for (var i = 0; i < values.length; i++){
var cypher = values[i];
aService.aFn.(array[cypher],cb);
}
//calls aService.aFn separately for each value array[1] , array[5] , array[7] passed as args