proposal-array-last
proposal-array-last copied to clipboard
Negative indexes with array.get(-1) and array.set(-1, value)
.get(-1)
and .set(-1, value)
have gotten a lot of support in #5, but since it's a separate proposal (and hasn't gotten a response from @keithamus yet), I figure it probably deserves its own issue.
Summary of reasons to favor it:
- they allow access to arbitrary distances from the end, not just the last value
- they're consistent with
Map
- they don't use getters/setters, which are a bit too magical for my tastes (setters especially – setting a property shouldn't have any side effect other than setting that property)
- they can be polyfilled in ES3 engines
@rauschma mentioned "I remember there were arguments against those methods, but forgot what they were", but I've yet to find any arguments against this idea.
Looking at the comments in #5, I count 17 people in support (3 comments and 14 other thumbs-ups) and no opposition.
It's a good idea, I think to have something like in Python where you could write arr[:-1]
or something that would be better and shorter.
Would set
follow in the steed of Map
and WeakMap
with regards to returning the array object instead of the value... In retrospect some regard this as an over-site that with enough will, would wish to see improved with the addition a put
method.
That is array.set(-1, value)
could either return array
or value
. The former is what Weak(Map)
do.
I do like set/get
much more than any single non-indexable getter/setter
pair.
It could also return undefined
; but I’d find array
most useful and consistent.
I'm not opposed to the idea, on the surface it seems good. There are two concerns with this though:
Yeah, I think that was the "I remember there were arguments against those methods, but forgot what they were".
I think this would be very worth it, even renamed for compat issues, getItem
/setItem
, or getAt
/setAt
, or possibly itemAt
/setItemAt
matching String#charAt
.
Edit: formatting
What about array.at(-1)
for reading, array.put(-1, value)
for writing, and array.index(-1)
to resolve indices? array.index(n)
would return -1
if n
out of bounds and the rest would throw, for safety and sanity.
Here's an optimized polyfill, derived from my polyfill of the current proposal here: https://github.com/keithamus/proposal-array-last/issues/26
const floor = Math.floor
function computeIndex(l, n) {
l = floor(l)
n = floor(n)
if (l !== l || n !== n) return 0
if (l >= 0) {
if (l > 9007199254740991) l = 9007199254740991
if (n < 0) {
n += len
if (n <= 0) return 0
}
if (n < l) return n
}
return -1
}
function install(name, func) {
if (Object.getOwnPropertyDescriptor(Array.prototype, name) == null) {
Object.defineProperty(Array.prototype, name, {
enumerable: false,
configurable: false,
writable: true,
value: func,
})
}
}
install("index", function index(n) {
if (this == null) throw new TypeError("`this` must be coercible to an object")
return computeIndex(+this.length, +n)
})
install("at", function at(n) {
if (this == null) throw new TypeError("`this` must be coercible to an object")
const index = computeIndex(+this.length, +n)
if (index < 0) throw new RangeError("index is out of range")
return this[index]
})
install("put", function put(n, value) {
if (this == null) throw new TypeError("`this` must be coercible to an object")
const index = computeIndex(+this.length, +n)
if (index < 0) throw new RangeError("index is out of range")
this[index] = value
})
This implements the following algorithm:
Abstract Operation: ResolveIndex(O, offset)
- ! RequireObjectCoercible(O).
- Let length be ? ToLength(Get(O,
"length"
)). - Let realOffset be ? ToInteger(offset).
- If realOffset is +∞, return -1.
- If realOffset is -∞, return 0.
- If realOffset < 0, set realOffset to max(realOffset + length, 0).
- If realOffset < length, return realOffset.
- Return -1.
Array.prototype.index(offset)
- Let O be the this value.
- ? RequireObjectCoercible(O).
- Return ResolveIndex(O, offset).
Array.prototype.at(offset)
- Let O be the this value.
- ? RequireObjectCoercible(O).
- Let index be ? ResolveIndex(O, offset).
- If index is -1, throw a RangeError exception.
- Return Get(O, ! ToString(index)).
Array.prototype.put(offset, value)
- Let O be the this value.
- ? RequireObjectCoercible(O).
- Let index be ? ResolveIndex(O, offset).
- If index is -1, throw a RangeError exception.
- Return Set(O, ! ToString(index), value).