Should negative indexes in JavaScript arrays contribute to array length?

JavascriptArrays

Javascript Problem Overview


In javascript I define an array like this

var arr = [1,2,3];

also I can do

arr[-1] = 4;

Now if I do

arr = undefined;

I also lose the reference to the value at arr[-1].

SO for me logically it seems like arr[-1] is also a part of arr.

But when I do following (without setting arr to undefined)

arr.length;

It returns 3 not 4;

So my point is if the arrays can be used with negative indexes, these negative indexes should also be a part of their length**. I don't know may be I am wrong or I may be missing some concept about arrays.

Javascript Solutions


Solution 1 - Javascript

> SO for me logically it seems like arr[-1] is also a part of arr.

Yes it is, but not in the way you think it is.

You can assign arbitrary properties to an array (just like any other Object in JavaScript), which is what you're doing when you "index" the array at -1 and assign a value. Since this is not a member of the array and just an arbitrary property, you should not expect length to consider that property.

In other words, the following code does the same thing:

​var arr = [1, 2, 3];arr.cookies = 4;

alert(arr.length) // 3;

Solution 2 - Javascript

The length property will return a number one higher than the highest assigned "index", where Array "indexes" are integers greater than or equal to zero. Note that JS allows "sparse" arrays:

var someArray = [];
someArray[10] = "whatever";
console.log(someArray.length); // "11"

Of course if there are no elements then length is 0. Note also that the length doesn't get updated if you use delete to remove the highest element.

But arrays are objects, so you can assign properties with other arbitrary property names including negative numbers or fractions:

someArray[-1] = "A property";
someArray[3.1415] = "Vaguely Pi";
someArray["test"] = "Whatever";

Note that behind the scenes JS converts the property names to strings even when you supply a number like -1. (The positive integer indexes also become strings, for that matter.)

Array methods, like .pop(), .slice(), etc., only work on the zero-or-higher integer "indexes", not on other properties, so length is consistent on that point.

Solution 3 - Javascript

Note that when you use a position (or 0) index, values are placed within the array:

var array = [];

array[0] = "Foo";
array[1] = "Bar";

// Result: ["Foo", "Bar"]
// Length: 2

This is not the case when you add non-index values (not 0-9+):

var array = [];

array[0]  = "Foo";
array[1]  = "Bar";
array[-1] = "Fizzbuzz"; // Not a proper array index - kill it

// Result: ["Foo", "Bar"]
// Length: 2

Values are only placed in the array when you play by the rules. When you don't, they aren't accepted. They are however accepted on the Array object itself, which is the case with just about anything in JavaScript. Even though ["Foo", "Bar"] are the only values in our array, we can still access "Fizzbuzz":

array[-1]; // "Fizzbuzz"

But note again that this isn't part of the array values, since its "index" isn't valid. It was instead added onto the array as just another member. We could access other array members in the same fashion:

array["pop"]; // function pop() { [native code] }

Note here that we're accessing the pop method on the array, which informs us that this contains native code. We're not accessing any of the array values with a key of "pop", but rather a member on the array object itself. We can further confirm this by cycling over the public members of the object:

for (var prop in array) 
    console.log(prop, array[prop]);

Which spits out the following:

 0 Foo
 1 Bar
-1 Fizzbuzz

So again, it's on the object, but it's not in the array.

Awesome question! Caused me to do a double-take for sure.

Solution 4 - Javascript

If you really want negative indexes and other indexes to be included in the length, then create the functionality yourself:

function getExtendedArray() {
	var a = [];

	Object.defineProperty(a, 'totalLength', { 
        get : function() { return Object.keys(a).length; }
    });
	
	return a;
}

Then for example:

var myArray = getExtendedArray();
console.log(myArray.totalLength); // 0
myArray.push("asdf");
myArray[-2] = "some string";
myArray[1.7777] = "other string";
console.log(myArray.totalLength); // 3

Solution 5 - Javascript

Arrays in JavaScript are actually objects. They are simply prototyped from the Array constructor.

Array indices are actually keys in a hashmap, and all keys are converted to strings. You can create any key (i.e. "-1"), but the methods on Array are tailored to act like an array. So length isn't the size of the object, it's rather only guaranteed to be larger than the largest integer index. Similarly, printing arr will only list values with integer keys >= 0.

More info here.

Solution 6 - Javascript

Array is just a special kind of Object in JS. There is a special syntax, which is good, because it allows us to work with them effectively. Imagine how tedious would it be to write an array literal that way:

const array = {0: 'foo', 1: 'bar', 2: 'baz'} //etc...

But they are still objects nevertheless. So if you do:

const myArray = [42, 'foo', 'bar', 'baz'];

myArray[-1] = 'I am not here';
myArray['whatever'] = 'Hello World';

Those non-integer properties will be attached to an object (which array is), but there are not accessible by some native methods like Array.length.

You can assume that the native 'length' method is a getter which counts all properties (and indexes are properties, while values are the actual values) convertible to positive integer or zero. Something like this pseudo-implementation:

Due to specs, the native length method – as a getter (exampleArray.length) – will check all 'nonnegative integer less than 232' keys, get the greatest one and return its numeric value + 1.

As a setter (exampleArray.length = 42), it will either create some empty slots for 'missing' indices if the given length is greater than the actual number of nonnegative integer keys, or delete all nonnegative integer keys (and their values) which are not greater then the given length.

The pseudo-implementation:

const myArray = {
  '-1': 'I am not here', // I have to use apostrophes to avoid syntax error
  0: 42,
  1: 'foo',
  2: 'bar',
  3: 'baz',
  whatever: 'Hello World',

  get myLength() {
    let highestIndex = -1;
    for (let key in this) {
      let toInt = parseInt(key, 10);
      if (!Number.isNaN(toInt) && toInt > -1) {
        // If you're not an integer, that's not your business! Back off!
        if (toInt > highestIndex) highestIndex = toInt;
      }
    }
    return highestIndex + 1;
  },
  set myLength(newLength) {
    /* This setter would either:
      1) create some empty slots for 'missing' indices if the given length is greater than the actual number of non-negative-integer keys
      2) delete all non-negative-integer keys (and their values) which are not greater then the given length.
    */
  }
}

console.log(myArray.myLength); // 4

myArray[9] = 'foobar';

console.log(myArray.myLength); // 10

Solution 7 - Javascript

According to MDN:

> The value of the length property is an integer with a positive sign and a value less than 2 to the 32 power (232)

In Javascript you can set a property on any object you create.

var array = new Array();
array = [1,2,3];
array["boom"] = "pow";

In the same way when you set a negative index it stores it as a property on the array rather than part of the index.

array[-1] = "property does not add to array length";

This is why the length doesn't reflect it but a for..in loop shows it.

Solution 8 - Javascript

When you use non-positive or non numeric indexes the array behaves as an associative array which has key-value pairs.

To iterate through the array you can use

for(var index in myArray) {
  document.write( index + " : " + myArray[index] + "<br />");
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionme_digvijayView Question on Stackoverflow
Solution 1 - JavascriptAndrew WhitakerView Answer on Stackoverflow
Solution 2 - JavascriptnnnnnnView Answer on Stackoverflow
Solution 3 - JavascriptSampsonView Answer on Stackoverflow
Solution 4 - JavascriptDavid SherretView Answer on Stackoverflow
Solution 5 - JavascriptTony RView Answer on Stackoverflow
Solution 6 - JavascriptHynekSView Answer on Stackoverflow
Solution 7 - JavascriptktilcuView Answer on Stackoverflow
Solution 8 - JavascriptAshanView Answer on Stackoverflow