Javascript Array Showing Inconsistent Behavior - javascript

I am confused regarding javascript arrays and how the indices work in these arrays. The length of the array is always 0 no matter how many key value elements are there in the array. Also we can see that the array has only two elements provided that the key is string. Lets consider scenario 1, i have following code.
arr = [];
arr['home'] = 1234;
arr['cat'] = 12345;
console.log(arr.length);
console.log(arr);
Now consider second scenario, i have an empty array and i assign some number to the 20th index of the array. Then when i output the array, the length shows 21 with all the other locations being 'undefined'.
arr = [];
arr[20] = 20;
console.log(arr.length); // Length shows 20 Size of array increased to 21
Now in the third scenario i will assign both numbered indices and string indices and it shows another strange behavior. The length of the array doesn't count the value with string based index. Even though i have 4 number indices and one string based index. So the length should be 6 but the length shows 5.
arr = [];
arr[4] = 4;
arr['home'] = 'home';
console.log(arr);
Now i have two questions.Firstly, Why is the length function not considering string indexed item? Secondly, Why in the case of numbered indices, does the array size is increased to atleast that number?

You have to understand that JavaScript arrays are objects, with some additional behavior. Just like objects, you can assign properties to them.
If the property's name is a numeric string and there is no higher numeric key, the length property is updated. Non-numeric keys don't affect the length property.
The methods in Array.prototype (filter, slice, ...) only work with the numeric keys of the array.

Javascript doesn't have associative arrays like you see in PHP. It has arrays, which have a numerical index associated with the value, and then it has objects which are mapped key => value.
Javascript Arrays and Javascript Objects
const arr = [1, 2, 3, 4, 5, 6, 7];
console.log(arr.length); // outputs 7
const obj = {}
console.log(obj.length); // undefined
// set the key => value for obj from arr
arr.forEach(a => obj[a] = a);
console.log(obj[0]); // undefined
console.log(obj[1]); // 1
console.log(arr[0]); // 1
console.log(arr[1]); // 2
JS Bin
In the example above, you can see that arr is an array and its values are mapped index => value, while obj is an object and its values are mapped key => value. Objects can function as hash maps/associative arrays, but arrays cannot.
If you were to want to get the number of values in an object/hash map, you can always do...
Object.keys(obj).length
This is because Object.keys(...) returns the keys of an object as an array.
For an accurate answer, I should clarify that arrays are objects, however, they function differently than an object inherently does. Per the docs, arrays are "high-level, list-like objects"

Related

Use Number to convert string to numbers in a copy of an array after using slice and spread operator

I wasn't able to find an exact solution or if it is even possible.
I have an example array and I wont be using the first two values, and I wanted to transform those strings to numbers with Number() and using the spread operator to convert each value in one go.
let array = ['1','2','3','4','5','6']
let result = Number(...array.splice(2));
the result of this is 3 is there a way to use the spread operator? or the only way out of this is to use map.
The expected result is result = [3,4,5,6] so only numbers. The array of strings is just an example, it might have more strings inside or less.
The Number constructor converts one value to a number - Number(value)
You're putting in as value a spreaded array from which the first value is taken and converted
Number(...array.splice(2)) // Number('3','4','5','6') => 3
I don't see any good example using the spread operator, since you don't want to get rid of the array structure, but have to iterate the array for converting each element from string to number
For getting rid of the first two entries without altering the original array use .slice() The second argument can be omitted if you want to slice from the index to the end of the array
To keep it short you can directly map on the spliced array using either the Number(v) constructor or by simply adding the + at the front
let array = ['1','2','3','4','5','6']
let numbers1 = array.slice(2).map(str => +str) // [3, 4, 5, 6]
let numbers2 = array.slice(2).map(str => Number(str)) // [3, 4, 5, 6]
One possible solution is slice the array (to remove the two first elements) and then map, transform the numbers from string to number:
let array = ['1','2','3','4','5','6']
let result = array.slice(2, array.length)
let numbers = result.map(el=>Number(el))
console.log(numbers)
You can choose to use splice, but you don't want the result. You just want to run that to remove the first 2 values. Then map the remaining values to an array of numbers and you're good.
let array = ['1','2','3','4','5','6'];
array.splice(0, 2); // splice will remove indexes 0 and 1
let result = array.map(n => +(n)); // map the remaining values to numbers
console.log(result);

Empty array with length different from zero. Can you explain me this?

var myNumb = 5;
var myArr = Array(myNumb);
console.log(myArr.length); // 5
console.log(myArr[0]) // undefined, as well as for myArr[1] myArr[2] myArr[3] myArr[4]
These lines create an array myArray that has a length of 5, but it's also said "an empty array", in fact myArr[0] is undefined, for example.
I can't understand how is possible to have an empty array with a length different from zero. If the array has not items, how can it have a length different from zero?
Positions in an array are still there even if they have no value, they are empty. Say you have the following code:
var myArray = new Array(5);
myArray[4] = 'Hello';
Do you expect 'Hello' to be in position 0 or 4? The answer is, of course, 4. The array has a length of 5, and even if indices 0 to 3 are empty, index 4 has a value.
As per MDN documentation, using the Array constructor yields the following:
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 its length property set to that number (Note: this implies an
array of arrayLength empty slots, not slots with actual undefined
values). If the argument is any other number, a RangeError exception
is thrown.
JavaScript Array

filter the objects with array using ES6

How to find the length of the ARRAY using ES6:
var x = [{a:"apple", b:"Baloon"},{a:"elephant", b:"dog"}];
var results = x.filter(aValue => aValue.length > 3);
console.log(results);
Note:
aValue.length would have worked if this is individual list of array. However, since these are values assigned to properties. Ex; a: apple, diff approach required.
What's the correct code that I need to replace "aValue.length" to find the length of the value greater than 3, so the answer would be apple, baloon and elephant ?
This will work for your needs
var results = x.filter(val => Object.keys(val).length > 3)
The Object.keys() method returns an array of all the keys contained in your object.
Objects do not have a length property. But there is a little trick with which you can have the number of keys of an object.
There are 2 methods that can be used. Object.getOwnPropertyNames(val).length and Object.keys(val).length
However, there is a little difference between the two. Object.getOwnPropertyNames(a) returns all own properties of the object a. Object.keys(a) returns all enumerable own properties.

How length property of an array works in javascript?

In javascript is it possible to directly set length property of an array. For example I can shorten the array like this:
var arr = [1, 2, 3, 4];
arr.length = 2;
console.log(arr); // Array [ 1, 2 ]
// arr[2], arr[3] are deleted
I would expect the length to be read-only (e.g. as in java).
As I understand, array in javascript is also an object:
console.log(typeof [1, 2, 3]); // object
How the length property works under the hood?
Array.prototype.length is a writable property of array.
Adding description from Array#lengthMDN
You can set the length property to truncate an array at any time. When you extend an array by changing its length property, the number of actual elements does not increase; for example, if you set length to 3 when it is currently 2, the array still contains only 2 elements. Thus, the length property does not necessarily indicate the number of defined values in the array.
This can be used to shorten an array.
As I understand, array in javascript is also an object:
console.log(typeof [1, 2, 3]); // object
Check Why does typeof array with objects return "Object" and not "Array"?
Generally, the length property is determined based on the highest index in the array.
Reading the length
1) For a dense array, this means that the length corresponds strictly to the number of elements:
var fruits = ['orange', 'apple', 'banana']; //fruits is a dense array
fruits.length // prints 3, the real count of elements
fruits.push('mango');
fruits.length // prints 4, one element was added
var empty = [];
empty.length // prints 0, empty array
The dense array does not have empties and the number of items corresponds to highestIndex + 1. In [3, 5, 7, 8] the highest index is 3 of element 8, thus the array size is 3 + 1 = 4.
2) In a sparse array (which has empties), the number of elements does not correspond to length value, but still is determined by the highest index:
var animals = ['cat', 'dog', , 'monkey']; // animals is sparse
animals.length // prints 4, but real number of elements is 3
var words = ['hello'];
words[6] = 'welcome'; //the highest index is 6. words is sparse
words.length //prints 7, based on highest index
Modifying the length
1) Modifying the property leads to cut the elements (if the new value is smaller than the highest index):
var numbers = [1, 3, 5, 7, 8];
numbers.length = 3; // modify the array length
numbers // prints [1, 3, 5], elements 7 and 8 are removed
2) or creating a sparse array (if the new value is bigger than the highest index):
var osTypes = ['OS X', 'Linux', 'Windows'];
osTypes.length = 5; // creating a sparse array. Elements at indexes 3 and 4
// do not exist
osTypes // prints ['OS X', 'Linux', 'Windows', , , ]
Please read this post, which covers in details everything about the length of an array.
The necessary steps to be fulfilled when length is being set on an Array is described on section 9.4.2.4 ArraySetLength of ES 6.0 language specification.
It deletes index properties from the old length of the array to the new length of the array according to step 19:
While newLen < oldLen repeat,
Set oldLen to oldLen – 1.
Let deleteSucceeded be A.[[Delete]](ToString(oldLen)).
Assert: deleteSucceeded is not an abrupt completion.
If deleteSucceeded is false, then
Set newLenDesc.[[Value]] to oldLen + 1.
If newWritable is false, set newLenDesc.[[Writable]] to false.
Let succeeded be OrdinaryDefineOwnProperty(A, "length", newLenDesc).
Assert: succeeded is not an abrupt completion.
Return false.
Whenever you set up a property for the array, it checks first to see if the property is length and if it is, it's supposed to do the ArraySetLength operation. This operation is described in section 9.4.2.1 [[DefineOwnProperty]] (this for Array Exotic Objects).
When the [[DefineOwnProperty]] internal method of an Array exotic object A is called with property key P, and Property Descriptor Desc the following steps are taken:
Assert: IsPropertyKey(P) is true.
If P is "length", then
Return ArraySetLength(A, Desc).
If it's not length and it's an indexed property the other steps in the operation are performed. Basically sets the value of the length property to the value of the index property + 1. As far as I can tell, the ArraySetLength operation isn't being used here to set the new length of the array.
Is it possible ?
Yes, it's possibly to directly set length property of an array.
You could set length of array to be shorten or higher ( to create sparsed array) then existing array. That's the way you can achieve desired behaviour.
Information about that from First edition of EcmaScript Standart-262, 15.4 :
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.
So when you assigned lower value of length than it was before for an array deleting items( they would be collected by garbage collector ECMA-262, 15.4.5.1) from that array.
How length determined ?
The length of an array is the highest index + 1. However you can update length of Array in both direction ( decrease to delete elements and increase to create sparsed Array).
How to create Array with defined length ?
To create Array with defined length, pass length value into Array constructor as in code below:
var length = 10;
var newArray = Array(length);
console.log(newArray.length);// 10
Use full links:
Mozzilla MDN Array
Delete JavaScript Array Elements
W3Schools JavaScript Array length Property
arr = arr.slice(0, 2); will give you the first 2 elements of the array as a new array.
I would say this method is much more clear than using array.length = number to set the length of an array.
From the specs :
Array objects give special treatment to a certain class of property
names.
...
whenever a property of an Array object is created or changed, other
properties are adjusted as necessary to maintain this invariant.
Basically since the built-in array methods like join, slice, indexOf, etc all get affected by the property change, it is also necessary to update the Array.
In this case, since length is changed, there will be a change to the keys in the array.
You may take a look to Paragraph 9.4.2: Array Exotic Objects, and subsequent paragraph "ArraySetLength" where is described the algorithm:
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 2 32 . 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.

JavaScript array's length method

Can anyone explain why the second alert says 0 ?
var pollData = new Array();
pollData['pollType'] = 2;
alert(pollData['pollType']); // This prints 2
alert(pollData.length); // This prints 0 ??
The length of the array is only changed when you add numeric indexes. For example,
pollData["randomString"] = 23;
has no effect on length, but
var pollData = [];
pollData["45"] = "Hello";
pollData.length; // 46
changes the length to 46. Note that it doesn't matter if the key was a number or a string, as long as it is a numeric integer.
Besides, you are not supposed to use arrays in this manner. Consider it more of a side effect, since arrays are objects too, and in JavaScript any object can hold arbitrary keys as strings.
Because you haven't put anything into the array yet. You've only been assigning to a dynamically-created pollType attribute on the array object.
If you use numeric indices, then the array automagically takes care of length. For example:
var arr = [ ]; // same as new Array()
arr[2] = 'Banana!';
alert(arr.length); // prints 3 (indexes 0 through 2 were created)
The length property takes into consideration only those members of the array which names are indexes (like '1', '2', '3', ... ).
Arrays in JavaScript have numeric indexes only.
Use an object, which is essentially what you are doing above, setting properties on that array object.
array.length returns how many values are stored in the array. The first alert is returning the value of the position 'pollType'.
The reference guide I always use when needing help with javascript arrays is this page http://www.hunlock.com/blogs/Mastering_Javascript_Arrays
I'd also read what it says under the heading Javascript Does Not Support Associative Arrays, as you may run into problems with this also.
var pollData = Array();
function test() {
pollData[0] = 2
alert(pollData[0]);
alert(pollData.length);
}
//[x] is the array position; hence ['polltype'] is causing issues

Categories

Resources