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:
Top comments (16)
I'm planning to build something similar, but with 'safe' monkey patching using Symbols. I think I'll end up with a syntax something like:
Or maybe (not sure this is possible safely):
Which syntax do you prefer? (I'm leaning towards the former)
Could even expand it to:
etc.
It's an amazing idea, Jon. I find the second option more readable. Or, at least, it feels "righter". But I'm not sure it could work since a function cannot be used as a key in a plain object.
Anyway, I'd like to work on it, together. Would you like to?
I already did a POC in about 5 lines of code - works perfectly
Still trying to think of a way to make the second syntax work without unsafe monkey patching. I'm not sure it's possible. My POC uses the
a[to](b)
syntax. Basically,to
is a method on the number prototype... nothing particularly fancy going onI think there is a way to do the 2nd syntax... I'll get back to you
It works 👍 And it's safe
I'm glad to read it. If you like to share I'd love to see it!
I noticed in your header image, you have
(3)(7)
- that's not gonna workOps, thank you man! This is what happens when you write posts at 2 a.m. :)
I'm gonna fix it
shshshsh
This is too much magic for me, don't comment to argue, I don't like it I won't change my mind but you can like it.
Hi Adam, I understand you point of view. As I stated in the post, this is something superfluous, a dev can definitely live without it :)
It's not that, I woke up on the wrong side of the bed and I saw prototype of native primitive type being modified and it's just not my bag. Sorry if this came across in any other way but grumpy 😜
Me too! Thank you!