I am learning Javascript. As a part of learning, I came across following scenario, where I expect the a1.length (the last line of the code) to show 201, but it shows 101, any Idea?
var a1 = new Array();
for (var i = -100; i<=100; i++)
a1[i] = i;
for (var i in a1)
{
document.write(i + "=" + a1[i])
document.write("<br>");
}
document.write(a1.length);
I'll convert my original comment to a more thorough answer.
Array indexes that are counted in .length go from 0 and up. Negative indexes are considered properties of the object, not array values. As you can see from the ECMAScript spec below, array indexes are essentially just certain types of property values given some special treatment.
From section 15.4 of the ECMAScript spec:
15.4 Array Objects
Array objects give special treatment to a certain class of property names. A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 2^32. A property whose property name is an array index is also called an element. Every Array object has a length property whose value is always a nonnegative integer less than 2^32 . The value of the length property is numerically greater than the name of every property whose name is an array index; whenever a property of an Array object is created or changed, other properties are adjusted as necessary to maintain this invariant. Specifically, 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. This constraint applies only to own properties of an Array object and is unaffected by length or array index properties that may be inherited from its prototypes.
Also, you should never "iterate" arrays with a for-in-loop:
for (var i in a1)
That iterates all enumerable properties of a1 which will include all array indexes, but could also include other properties. If you want to iterate only array elements with a for loop, you should use the other form:
for (var i = 0, len = a1.length; i < len; i++)
It is slightly more typing, but a lot safer.
Or, in more modern browsers, you can use the .forEach() method.
It is because arrays in Javascript are zero-based, i.e. they start from zero and go up to length - 1.
You usually write your for loops to be bound by less-than operator like this:
for(i = 0; i < arr.length; i++) {
// do something with arr[i]
}
The array length is defined as the index of the last element plus one. Arrays do not need to be continuous, which can give strange results:
var myArray = [];
myArray[-42] = 1
myArray[1000] = 2;
document.write(myArray.length); // 1001
Related
This question already has answers here:
javascript for loop counter coming out as string [duplicate]
(3 answers)
Closed 3 years ago.
For example
var a = [1, 2, 3];
for (var i in a) {
console.log(typeof i);
}
Output
string
string
string
I am a Python programmer, and I find it very unintuitive. Why is not an element evaluated to be a number instead?
You are looping over the keys of the object. Meaning the keys you are actually testing is "0", "1", "2".
You can see that here, if you also console the i. Also, if you console the value that is located at that index in the array, and test that, you will see that it is a number:
var a = [1, 2, 3];
for (var i in a) {
console.log(i, typeof i, a[i], typeof a[i]);
}
In ES5, a new feature was added to arrays that loops through their values (and indexes): Array#forEach:
var a = [1, 2, 3];
a.forEach(function(v) {
console.log(v, typeof v);
});
In ES2015+, for-of was added, which will loop through the values using a for-style loop:
// ES2015+ only!!
let a = [1, 2, 3];
for (let v of a) {
console.log(v, typeof v);
}
why the type of a number element in an array is evaluated to be a string in javascript
If you really mean the element, not the index, then the problem is that you're just looking at the type of the wrong thing. See KevBot's answer.
If you're asking why the indexes (0, 1, and 2) are strings rather than numbers, since array indexes are normally numbers, it's because standard arrays in JavaScript aren't really arrays at all, they're just objects with some special behavior:
An Array object is an exotic object that gives special treatment to array index property keys (see 6.1.7). A property whose property name is an array index is also called an element. Every Array object has a length property whose value is always a nonnegative integer less than 232. The value of the length property is numerically greater than the name of every own property whose name is an array index; whenever an own property of an Array object is created or changed, other properties are adjusted as necessary to maintain this invariant. Specifically, whenever an own property is added whose name is an array index, the value of the length property is changed, if necessary, to be one more than the numeric value of that array index; and whenever the value of the length property is changed, every own property whose name is an array index whose value is not smaller than the new length is deleted. This constraint applies only to own properties of an Array object and is unaffected by length or array index properties that may be inherited from its prototypes.
Until ES2015, all object property names were strings. (Now they can be either strings or Symbols.) Array indexes are just property names that conform to a specific definition:
A String property name P is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 232-1.
See also A myth of arrays (on my blog).
I am trying to copy one array values into another, but without breaking the links that is associated with this array other words i can not just assign the new array to this value, thats why i cannot use methods like slice() or concat().
Here is the code of the function that does the thing:
self.updateBreadcrumbs = function (newBreadcrumbs) {
var old_length = self.breadcrumbs.length;
var new_length =newBreadcrumbs.length;
var j = new_length > old_length ? new_length: old_length;
for (var i = 0; i < j; i++) {
if(old_length < i+1){
self.breadcrumbs.push(newBreadcrumbs[i]);
continue;
}
if(new_length < i+1){
delete self.breadcrumbs[i];
continue;
}
if (self.breadcrumbs[i].title !== newBreadcrumbs[i].title) {
self.breadcrumbs[i] = newBreadcrumbs[i];
}
}
}
My problem is that length of the array does not change when i delete something from the array.
P.S If you know any easier way to do this i am totally open for propositions.
Length of an Array can never change by deleting elements in it.
However It can be altered with splice
eg.
var arr=[1,2,3,4,5]; //length 5
arr.splice(0,1); //length 4
Unlike what common belief suggests, the delete operator has nothing to do with directly freeing memory. delete is only effective on an object's properties. It has no effect on array length
The splice() method changes the content of an array by removing
existing elements and/or adding new elements.
More about Splice
The length property of an Array object is a property that is maintained by it's methods, it is not an inherent characteristic of the object itself. So, if you take an action on it that is not one of Array's own methods, it will not update the length property. In this case, it is the splice method that you would want to use ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice )
Interestingly, you can change the makeup of an array by directly altering its length . . . for example, if you have an array with 6 elements in it and you were to change its length property to 5 (i.e., array.length = 5;), it would no longer recognize the 6th element as being part of the array.
More on the length property: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length
An Array is (aside from its prototype methods) not much more than a simple object. The difference is in the length property which has a spcieal setter method, and the different way of adding a new property.
If a property is added to the object, its name is tested for being a numerical value and whether this value is >= the current array length. if so, the internal length is updated.
If the length is set, it is checked, whether the new value is smaller than the old one, and if so, all own properties with a property name that is a numerical value and >= the new length will be deleted.
If you delete an indexed element from an array, it will just be deleted (and accessing this index later will return undefined, as it would do with any non-existent property). It won't change the array length, nor will increasing the array length create any properties for the added index positions (sparse array). Using [] or new Aray[10000] will both create Arrays with exactly the same memory footprint. Just the length property has a different initial value.
This is completely different from Arrays in other languages, where an array of size n will have n storage spaces reserved for the elements (being pointers to objects or being native value types). So in other languages, creating an array with a given size and filling it is faster than creating an empty array and adding values (in which case each time a larger consecutive space must be allocated and the array must be copied to this larger memory psoition before adding the element). OTOH, accessing the elements of an JS array is somewhat slower (as they are just named properties which have to be located in the property list first) than in other languages where an element is at its given, fixed position.
This answer will not help if you use array, but.
If you still need to delete item by key and you can use object:
$o = {'blue' : '', 'apple' : '', 'red' : ''};
console.log(Object.keys($o).length); // will output 3
delete $o['apple'];
console.log(Object.keys($o).length); // will output 2
For Example:
var arr = [];
arr[3.4] = 1;
console.log(arr.length);
In the above code sample the length property holds zero why and what happened inside JS parser because it's length is zero.
An array's length is reflective of the largest array index present in the array. An "array index" (see below) is a property name that is an integer value less than 232−1. Since 3.4 is not an integer, setting it does not alter the length.
Arrays are objects, so there is no reason why an array can't have a property named 3.4, but that property doesn't influence the length because its name does not fit the criteria of an array index.
ES2015 9.4.2, Array Exotic Objects defines an "array index" as an integer less than 232−1:
A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 232−1."
And that definition is used in relation to the length value (emphasis mine):
Every Array object has a length property whose value is always a nonnegative integer less than 232. The value of the length property is numerically greater than the name of every own property whose name is an array index; whenever an own property of an Array object is created or changed, other properties are adjusted as necessary to maintain this invariant. Specifically, whenever an own property is added whose name is an array index, the value of the length property is changed, if necessary, to be one more than the numeric value of that array index...
A JavaScript array can not have fractional indexes.
What you have done there is assigned a property called "3.4" on the array object.
This does not affect the length property, which is designed to return one number higher than the highest valid index.
If you think about how arrays are supposed to work, you should realise a fractional offset doesn't make sense.
You could try using an object vs an array.
var arr = {};
arr[3.4] = 1;
arr[3.5] = 2;
arr[3.6] = 3;
console.log(Object.keys(arr).length);
You must use an integer as an index, not a float.
var arr = [];
arr[3] = 1;
console.log(arr.length);
var arr = ["Hello", "There", 123, 456, {
show: function (value) {
alert(value);
}
}];
arr[4].show(arr[0]);
arr["Hello"] = {
damn: function () {
alert("What's happening yo !");
}
}
arr.Hello.damn();
alert("Arr length is: " + arr.length);
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 if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 232−1.
Since Hello is not valid, according to the above definition, it is not considered as an array index but just as an ordinary property.
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 length property accordingly
So, only if the property is a valid array index, the length property will be adjusted.
In your case, you have just created a new property Hello on the array object.
Note: Only the numerical properties will be used in all of the Array's prototype functions, like forEach, map, etc.
For example, the array shown in question, when used with forEach,
arr.forEach(function(currentItem, index) {
console.log(currentItem, index);
})
would print
Hello 0
There 1
123 2
456 3
{ show: [Function] } 4
even though the list of keys shows Hello.
console.log(Object.keys(arr));
// [ '0', '1', '2', '3', '4', 'Hello' ]
It is because, Array is derived from Object,
console.log(arr instanceof Object);
// true
and Hello is a valid key of the array object, but just not a valid array index. So, when you treat the array as an Object, Hello will be included in the keys, but the array specific functions will include only the numerical properties.
This happens because length is only updated when a new numeric property is added to the array as required by the specification:
The length property of this Array object is a data property whose value is always numerically greater than the name of every deletable property whose name is an array index.
And an array index is specified to be:
A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 232−1.
However, arrays are also objects - so you can add non-array-index properties to an array, just like you can add properties to any other JavaScript object (which is why your example doesn't throw either).
javascript length is calculated as 1+(highest numeric index element). so when you add arr['Hello'], you are only adding a string index which is not taken into account when calculating the array length.
This is the actual definition of the array length property as described in ECMAScript 5.1:
Every Array object has a length property whose value is always a
nonnegative integer less than 232. The value of the length property is
numerically greater than the name of every property whose name is an
array index; whenever a property of an Array object is created or
changed, other properties are adjusted as necessary to maintain this
invariant. Specifically, 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. This constraint applies only to own properties of an Array
object and is unaffected by length or array index properties that may
be inherited from its prototypes.
When you write:
arr["Hello"]=...
you are creating a new Object associated with the arr Array object, which does not affect the length of arr.
You can achieve the same effect by writing:
arr.Hello=...
Could someone explain this (strange) behavior? Why is the length in the first example 3 and not 2, and most importantly, why is the length in the second example 0? As long as the keys are numerical, length works. When they are not, length is 0. How can I get the correct length from the second example? Thank you.
a = [];
a["1"] = {"string1":"string","string2":"string"};
a["2"] = {"string1":"string","string2":"string"};
alert(a.length); // returns 3
b = [];
b["key1"] = {"string1":"string","string2":"string"};
b["key2"] = {"string1":"string","string2":"string"};
alert(b.length); // returns 0
One thing to note is that there is a difference between regular arrays and associative arrays. In regular arrays (real arrays), the index has to be an integer. On the other hand, associative arrays can use strings as an index. You can think of associative arrays as a map if you like. Now, also note, true arrays always start from zero. Thus in your example, you created an array in the following manner:
a = [];
a["1"] = {"string1":"string","string2":"string"};
a["2"] = {"string1":"string","string2":"string"}
Javascript was able to convert your string indexes into numbers, hence, your code above becomes:
a = [];
a[1] = {"blah"};
a[2] = {"blah"};
But remember what i said earlier: True arrays start from zero. Therefore, the javascript interpreter automatically assigned a[0] to the undefined. Try it out in either firebug or the chrome/safari console, and you will see something like this when you try to print "a". You should get something like "[undefined, Object, Object]. Hence the size 3 not 2 as you expected.
In your second example, i am pretty sure you are trying to simulate the use of an associated array, which essentially is adding properties to an object. Remember associated arrays enable you to use strings as a key. So in other terms, you are adding a property to the object. So in your example:
b["key1"] = {"string1":"string","string2":"string"};
this really means:
b.key1 = {"string1":"string","string2":"string"};
Initializing b =[] simply creates an array, but your assignment doesn't populate the array. It simply gives "b" extra properties.
length returns 1 + the largest integer key in the object.
In a the largest key is 2 so 1+2 is 3.
In b there are no integer keys (the keys there are key1 and key2 which cannot be converted into ints) so Javascript assumes that the largest key is -1, and 1 + -1 yields 0.
This program will help you see that:
a = [];
a["1"] = {};
a["4"] = {};
alert(a.length); // Prints 5
From the ECMAScript standard, ECMA-262, 5th ed.
15.4.5.2 length
The length property of this Array object is a data property whose value is always numerically greater than the name of every deletable property whose name is an array index.
Note the length property of an array only takes into account array indices, which are integers; setting other properties doesn't affect length.
For an array, a["3"] is equivalent to a[3] (this behavior is specified by § 15.4.5.1); 3 is an array index rather than a property. Thus setting a["3"] affects the array's length. b["key1"] is equivalent to b.key1. Setting properties don't affect the length of a collection.