Adding Negative Indexes to JavaScript Arrays

in javascript

Every time I return from ruby/python to JavaScript I'll fall into the same mistake of writing arr[-1] and not getting the last item. JavaScript has a weird way of stringifying object keys which leads to stringifying array indexes which renders the above nonsense there.

Luckily JavaScript is also great at monkey patching, so let's see if we can fix negative indexes there.

Take 1: -1 Is A Valid Index

Since JavaScript stringifies keys -1 is just as valid array index as foo, bar, 2 and 15. This means the following code works:

var items = [10, 20, 30, 40, 50];
items['-1'] = items[items.length - 1];

// Now we can read items[-1]
console.log('The last item is: ' + items[-1]);

And a codepen to prove it:

See the Pen Yrayme by Ynon Perek (@ynonp) on CodePen.

Take 2: -1 As A Property

Manually adding an attribute every time we create an array is not going to work in real world code. Luckily the same idea can be applied accross the board and more dynamically using Object.defineProperty.

We can add -1 as a property to Array.prototype. The following code thus works:

// Step 2:
var items = [10, 20, 30, 40, 50];
var otherItems = ['a', 'b', 'c', 'd'];

Object.defineProperty(Array.prototype, '-1', {
  get() { return this[this.length - 1] }

// 50

// d

And a codepen to prove it:

See the Pen KXoVPP by Ynon Perek (@ynonp) on CodePen.

As a bonus we can now modify the last item using a simple:

items[-1] = 'OMG Negative Indexes';

Take 3: Even More Negative Indexes

Now that we have -1 working let's try to add support for other negative indexes. If you know your maximum array count you may get away with using a loop. Generally though that's not going to hold.

What we can do is use proxies. A proxy intercepts all calls to a target, so one could catch all calls to property names which start with a dash and treat them as negative indexes. Here's the example codepen:

See the Pen LzdGpO by Ynon Perek (@ynonp) on CodePen.

The problem with this approach is that you can't apply it to existing programs because we can't override Array.constructor. It does help for the cases you need a more genric array access solution and you control its creation code.

My favorite is the second solution as I can just drop it into any JavaScript program and start using -1 to mean the last item in the array (which is my use case 99% of the times anyways).