I think there is room for—and a solid case to be made for—an alternative to the Array.prototype.at method that would take a finite integer as its sole argument, the index value of the desired element.
Similar to Array.prototype.at, Array.prototype.idx would support negative index values, but contrastingly, it would not be syntactical sugar for arr.slice(n)[0] but rather implement a new spec that would only accept an integer as its sole argument, representing the desired index.
In the case of negative values, negative indices would start at -0 (not -1) and descend from there.
Using the array ["a", "b", "c", "d", "e"] for example…
const arr = ["a", "b", "c", "d", "e"]
arr.idx(0) // -> "a"
arr.idx(1) // -> "b"
arr.idx(-0) // -> "e"
arr.idx(-1) // -> "d"
Adding a method supporting a -0 index would be vital in equal polarity in comparison. If a function takes in an index offset value as one argument and a direction (e.g. LFT/asc, RTL/dsc), the return value would be a simple calculation of the offset multiplied by the direction where the direction would be represented as either 1 or -1 which may in practice be calculated using Math.sign.
Using Array.prototype.at, this would require several additional checks…
- Firstly, checking to ensure the passed value is indeed a valid finite integer
- Secondly, checking to see if the direction is RTL/dsc and if the computed value would yield a negative index value, the function would have to subtract one from the desired negative offset value.
For example, if someone desired a value with an offset of 1 from the end of the array (the second from the end), the function would have to return an offset of -1 * (1+1) which computes to -2 in order to balance the -1 offset Array.prototype.slice imposes (by nature of length - 1) and return the desired value.
Using this proposed Array.prototype.idx method however, the desired return value would always be computed as offset * direction regardless of whether the value is positive or negative.
An offset of 0 from the end of the array (RTL) would be the equivalent of [1, 2, 3].idx(-0), yielding 3.
Regarding the proposed spec, accounting for -0 values is historically possible with logic like this:
function isNeg0(n) {
return n === 0 && Math.sign(Infinity / n) === -1
}
isNeg0(-1) // -> false
isNeg0(-0) // -> true
isNeg0(0) // -> false
isNeg0(1) // -> false
With the newer addition and now widespread support of Object.is(), detection of negative zero values is as simple as this logic:
function isNeg0(n) {
return Object.is(n, -0)
}
isNeg0(-1) // -> false
isNeg0(-0) // -> true
isNeg0(0) // -> false
isNeg0(1) // -> false
A modern JS spec for a method like Array.prototype.idx could look as simple as a wrapper of the Array.prototype.at method, which would not deviate away from the traditional coercion method at all but rather make use of it:
Array.prototype.idx = function(index) {
return this.at(index < 0 || Object.is(index, -0) ? index - 1 : index)
}
const arr = [1, 2, 3, 4, 5]
// positive index values
arr.idx(0) // -> 1
arr.idx(1) // -> 2
arr.idx(2) // -> 3
arr.idx(3) // -> 4
arr.idx(4) // -> 5
// negative index values
arr.idx(-0) // -> 5
arr.idx(-1) // -> 4
arr.idx(-2) // -> 3
arr.idx(-3) // -> 2
arr.idx(-4) // -> 1
// other values
arr.idx("foo") // -> 1
arr.idx(NaN) // -> 1
arr.idx(1.5) // -> 2