Objects don't have a .length property.
A simple solution if you know you don't have to worry about hasOwnProperty checks, would be to do this:
Object.keys(data).length;
If you have to support IE 8 or lower, you'll have to use a loop, instead:
var length= 0;
for(var key in data) {
if(data.hasOwnProperty(key)){
length++;
}
}
Answer from Cerbrus on Stack OverflowObjects don't have a .length property.
A simple solution if you know you don't have to worry about hasOwnProperty checks, would be to do this:
Object.keys(data).length;
If you have to support IE 8 or lower, you'll have to use a loop, instead:
var length= 0;
for(var key in data) {
if(data.hasOwnProperty(key)){
length++;
}
}
One option is:
Object.keys(myObject).length
Sadly it not works under older IE versions (under 9).
If you need that compatibility, use the painful version:
var key, count = 0;
for(key in myObject) {
if(myObject.hasOwnProperty(key)) {
count++;
}
}
Thanks to Pietro, I found the solutions via Google after knowing about Object.keys().
Object.keys(roles).forEach(function(key) {
console.log(key + ': ' + roles[key]);
});
For the guys who down voted, it's a new thing I learnt today about Object.keys(). Thanks for your encouragement by down voting. :)
It is not an Array, is clearly an Object.
The reason why you can access it using an Array-like notation is that JS supports the square brackets access notation. Since you have numbers as keys, it can be a bit misleading.
Note: Array indexes are nothing but properties of Array objects.
Quoting MDN's Relationship between length and numerical properties section,
When setting a property on a JavaScript array when the property is a valid array index and that index is outside the current bounds of the array, the engine will update the array's
lengthproperty accordingly.
Quoting ECMA Script 5 Specification of Array Objects,
whenever a property is added whose name is an array index, the length property is changed, if necessary, to be one more than the numeric value of that array index; and whenever the length property is changed, every property whose name is an array index whose value is not smaller than the new length is automatically deleted
So, when you set a value at index 5, JavaScript engine adjusts the length of the Array to 6.
Quoting ECMA Script 5 Specification of Array Objects,
A property name
P(in the form of a String value) is an array index if and only ifToString(ToUint32(P))is equal toPandToUint32(P)is not equal to 232−1.
So, in your case 2 and 4 are valid indexes but only 2 is defined in the array. You can confirm that like this
arr.hasOwnProperty(2)
The other indexes are not defined in the array yet. So, your array object is called a sparse array object.
So why arr[2] is counted in for..in loop and not arr[4] is not counted?
The for..in enumerates all the valid enumerable properties of the object. In your case, since only 2 is a valid property in the array, it will be counted.
But, when you print arr[4], it prints undefined, because JavaScript will return undefined, if you try to access a property which is not defined in an object. For example,
console.log({}['name']);
// undefined
Similarly, since 4 is not yet defined in the arr, undefined is returned.
While we are on this subject, you might want to read these answers as well,
Why doesn't the length of the array change when I add a new property?
JavaScript 'in' operator for
undefinedelements in Arrays
There’s a difference between a property that has the value undefined and a property that doesn’t exist, illustrated here using the in operator:
var obj = {
one: undefined
};
console.log(obj.one === undefined); // true
console.log(obj.two === undefined); // true
console.log('one' in obj); // true
console.log('two' in obj); // false
When you try to get the value of a property that doesn’t exist, you still get undefined, but that doesn’t make it exist.
Finally, to explain the behaviour you see: a for in loop will only loop over keys where that key is in the object (and is enumerable).
length, meanwhile, is just adjusted to be one more than whatever index you assign if that index is greater than or equal to the current length.
Arrays are zero-based indexing. Which means The first element of the array is indexed by subscript of 0 and last element will be length - 1
const arr = [2 , 3, 6, 8];
const end = arr[ arr.length - 1 ];
console.log(end);
JavaScript array indexes start counting at 0. So...
arr[0] evaluates to 2
arr[1] evaluates to 3
arr[2] evaluates to 6
arr[3] evaluates to 8
arr.length evaluates to 4 because there are 4 elements in your array
arr[4] refers to the 5th element in an array, which in your example, is undefined
That's because coordinates is Object not Array, use for..in
var coordinates = {
"a": [
[1, 2],
[8, 9],
[3, 5],
[6, 1]
],
"b": [
[5, 8],
[2, 4],
[6, 8],
[1, 9]
]
};
for (var i in coordinates) {
console.log(coordinates[i])
}
or Object.keys
var coordinates = {
"a": [
[1, 2],
[8, 9],
[3, 5],
[6, 1]
],
"b": [
[5, 8],
[2, 4],
[6, 8],
[1, 9]
]
};
var keys = Object.keys(coordinates);
for (var i = 0, len = keys.length; i < len; i++) {
console.log(coordinates[keys[i]]);
}
coordinates is an object. Objects in javascript do not, by default, have a length property. Some objects have a length property:
"a string - length is the number of characters".length
['an array', 'length is the number of elements'].length
(function(a, b) { "a function - length is the number of parameters" }).length
You are probably trying to find the number of keys in your object, which can be done via Object.keys():
var keyCount = Object.keys(coordinates).length;
Be careful, as a length property can be added to any object:
var confusingObject = { length: 100 };
Because the last element in the array is undefined.
The array has 3 elements 1, 2 and undefined where undefined has the index 2 and the array has a length of 3.
Thus when array[array.length - 1] is returned it is undefined
Because "undefined" is treated as an element of an array !!
The reason is that you're not logging superArray in your fetch promise. If you add the call to console.log() in your last then() call it works. The reason for this is that fetch is executed asynchronously, which means that any additional code that comes after the fetch call is executed long before the fetch has returned anything.
The reason you can see a full log of superArray even when doing it outside the fetch is a special console behaviour.
const URL1 = "https://www.politifact.com/api/statements/truth-o-meter/people/barack-obama/json/?n=50";
const URL2 = "https://www.politifact.com/api/statements/truth-o-meter/people/hillary-clinton/json/?n=210";
const URL3 = "https://www.politifact.com/api/statements/truth-o-meter/people/bernie-s/json/?n=70";
var superArray = [];
fetch("https://cors-anywhere.herokuapp.com/" + URL1)
.then(results => {
return results.json();
})
.then(data => {
data = data.filter(function(item) {
return item.speaker.name_slug == "barack-obama" && item.statement_type.statement_type !== "Flip";
});
for (var i = 0; i < 10; i++) {
superArray.push(data.splice(Math.random() * data.length, 1)[0]);
}
})
fetch("https://cors-anywhere.herokuapp.com/" + URL2)
.then(results => {
return results.json();
})
.then(data => {
data = data.filter(function(item) {
return item.speaker.name_slug == "hillary-clinton" && item.statement_type.statement_type !== "Flip";
});
for (var i = 0; i < 10; i++) {
superArray.push(data.splice(Math.random() * data.length, 1)[0]);
}
})
fetch("https://cors-anywhere.herokuapp.com/" + URL3)
.then(results => {
return results.json();
})
.then(data => {
data = data.filter(function(item) {
return item.speaker.name_slug == "bernie-s" && item.statement_type.statement_type !== "Flip";
});
for (var i = 0; i < 10; i++) {
superArray.push(data.splice(Math.random() * data.length, 1)[0]);
}
console.log(superArray[0]);
})
It's possible to be logged into your console before data is fetched. To make it sure, log that after accomplishing the data ie. inside .then().
fetch(...)
.then(results => {...})
.then(data => {...})
.then(()=> console.log(superArr[0]))
Or, you may use:
superArray.length && console.log(superArray[0]);
That's because length gives you the next index available in the array.
DOCS
arrayLength
If the only argument passed to the Array constructor is an integer between 0 and 2^32-1 (inclusive), this returns a new JavaScript array with length set to that number.
ECMA Specifications
Because you don't have inserted any element in the other keys than 21, 90, 13, all the remaining indexes contains undefined. DEMO
To get actual number of elements in the array:
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
var len = 0;
for (var i = 0; i < a.length; i++) {
if (a[i] !== undefined) {
len++;
}
}
document.write(len);
Shorter version
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
for (var i = 0, len = 0; i < a.length; i++, a[i] !== undefined && len++);
document.write(len);
DEMO
EDIT
If the array contains large number of elements, looping to get its length is not the best choice.
As you've mentioned in the question, Object.keys(arr).length is the best solution in this case, considering that you don't have any properties added on that array. Otherwise, the length will not be what you might be expecting.(Thanks To @RobG)
The array in JavaScript is a simple zero-based structure. The array.length returns the n + 1 where n is the maximum index in an array.
That's just how it works - when you assign 90'th element and this array's length is less than 90, it expands an array to 90 and sets the 90-th element's value. All missing values are interpreted as null.
If you try the following code:
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
console.log(JSON.stringify(a));
You will get the following JSON:
[null,null,null,null,null,null,null,null,null,null,null,null,null,{},null,null,null,null,null,null,null,{},null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,{}]
Moreover, array.length is not a readonly value.
If you set a length value less than the current, then the array will be resized:
var arr = [1,2,3,4,5];
arr.length = 3;
console.log(JSON.stringify(arr));
// [1,2,3]
If you set a length value more than the current, then the array will be expanded as well:
var arr = [1,2,3];
arr.length = 5;
console.log(JSON.stringify(arr));
// [1,2,3,null,null]
In case you need to assign such values, you can use JS objects.
You can use them as associative array and assign any key-value pairs.
var a = {};
a[21] = 'a';
a[90] = 'b';
a[13] = 'c';
a['stringkey'] = 'd';
a.stringparam = 'e'; // btw, a['stringkey'] and a.stringkey is the same
console.log(JSON.stringify(a));
// returns {"13":"c","21":"a","90":"b","stringkey":"d","stringparam":"e"}
console.log(Object.keys(a).length);
// returns 5
I would wager that one of the payrollDb[i] is undefined. After this line:
for(let i=0; i<payrollDb.length; i++) {
Add a check to log the [i] before your next loop. Then when it errors the location that is causing an issue should show up, and you should be able to code around it. You could also wrap the second for in a conditional to skip it if it's undefined.
for(let i=0; i<payrollDb.length; i++) {
if ([i] === undefined) { // check the type equals undefined
for(let j=0; j<payrollDb[i].length; j++) {
Well it seems I've found the issue. To be honest I am not sure why this worked but it did.
I added a variable prior to the loops equal to the length of the array I was about to loop through and then used that in my for loop instead of directly calling payrollDb.length or payrollDb[i].length.
The updated code is as follows.
function checkDupe(submissionId) {
let result;
let view;
// Set variable for outer array length
let n = payrollDb.length;
for(let i=0; i<n; i++) {
// Set variable for inner array length
let m = payrollDb[i].length;
for(let j=0; j<m; j++) {
payrollDb[i][j] === submissionId ? result = true : result = false;
}
};
result ? view = views_payroll_duplicate : view = views_payroll_period;
return view;
}
If somebody could explain further that would be great!!!
JavaScript doesn't have a .length property for objects. If you want to work it out, you have to manually iterate through the object.
function objLength(obj){
var i=0;
for (var x in obj){
if(obj.hasOwnProperty(x)){
i++;
}
}
return i;
}
alert(objLength(JSONObject)); //returns 4
Edit:
Javascript has moved on since this was originally written, IE8 is irrelevant enough that you should feel safe in using Object.keys(JSONObject).length instead. Much cleaner.
The following is actually an array of JSON objects :
var JSONObject = [{ "name":"John Johnson", "street":"Oslo West 16", "age":33,
"phone":"555 1234567"}, {"name":"John Johnson", "street":"Oslo West 16",
"age":33, "phone":"555 1234567" }];
So, in JavaScript length is a property of an array. And in your second case i.e.
var JSONObject = {"name":"John Johnson", "street":"Oslo West 16", "age":33,
"phone":"555 1234567"};
the JSON object is not an array. So the length property is not available and will be undefined. So you can make it as an array as follows:
var JSONObject = [{"name":"John Johnson", "street":"Oslo West 16", "age":33,
"phone":"555 1234567"}];
Or if you already have object say JSONObject. You can try following:
var JSONObject = {"name":"John Johnson", "street":"Oslo West 16", "age":33,
"phone":"555 1234567"};
var jsonObjArray = []; // = new Array();
jsonObjArray.push(JSONObject);
And you do get length property.