Built-in-like Range in JavaScript
Francesco Di Donato
Posted on October 6, 2021
Premise
Make it possible to generate any range of integers with built-in-like syntax.
Motivation?
Honestly, none. Zero. Except for fun & study.
Basic functionality
You start by overriding the prototype of Number
with itself, but proxed.
Object.setPrototypeOf(
Number.prototype,
new Proxy(Number.prototype, {
// ...
})
)
In this way, any normal operations related to the prototype are not lost.
In the proxy you listen for access to any property via a getter. The third argument (receiver
) is the "object", in this case the number itself - you call it start
. It's already the right type, number.
The second argument corresponds to the name of the property, its typeof
is indeed string
.
Object.setPrototypeOf(
Number.prototype,
new Proxy(Number.prototype, {
get(_, _end, start) {
// _end -> '182' (typeof string)
// start -> 42 (typeof number)
},
})
)
(42)[182]
It is sufficient to use parseInt
and, if it still isNaN
just throw an error/warning. Or just ignore it silently and fallback by returning start
.
let end = parseInt(_end)
if (isNaN(end)) {
// warning or error
// eventually, fallback
return start
}
Assured that the typeof end
is also number
, you can proceed to generate the range.
return Array(end - start + 1)
.fill()
.map((_, i) => start + i)
Basic functionality is complete. Now the following code is perfectly valid.
(0)[5] // [0, 1, 2, 3, 4, 5]
To make it not-end-inclusive, use
Array(end - start)
instead ofArray(end - start + 1)
.
Reverse range
To be able to do something like the following...
[5](0) // [5, 4, 3, 2, 1, 0]
Check if start > end
and if so swap both. Don't forget to sort the result in descending order.
The code is self-explanatory.
Object.setPrototypeOf(
Number.prototype,
new Proxy(Number.prototype, {
get(_, _end, start) {
// where (start)[_end]
let end = parseInt(_end)
if (isNaN(end)) {
// warning or error
// eventually, fallback
return start
}
// sort behaviour - default ASC
let s = +1
if (start > end) {
// swap
let tmp = start
start = end
end = tmp
// sort behaviour - DESC
s = -1
}
// generate range
return Array(end - start + 1)
.fill()
.map((_, i) => start + i)
.sort(() => s)
},
})
)
Result
42 // 42
(0)[5] // [0, 1, 2, 3, 4, 5]
(0)['foo'] // #fallback -> 0
(3)[7] // [3, 4, 5, 6, 7]
(8)[3] // [8, 7, 6, 5, 4, 3]
Couldn't I have done the same thing with a range function?
Yes, probably you should do it with a function.
Let this be a mental exercise and a way of making friends with the concept of prototype and proxy.
If you want to chat about nerdy things or just say hi, you can find me here:
Posted on October 6, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
October 20, 2024