Built-in-like Range in JavaScript

Scritto da Francesco Di Donato • 6 ottobre 2021 • 2 minuti di lettura
Motivazione? Onestamente, nessuna. Zero. A parte il divertimento e lo studio.
Funzionalità di base
Inizi sovrascrivendo il prototype di Number
con se stesso, ma prossato.
Object.setPrototypeOf(
Number.prototype,
new Proxy(Number.prototype, {
// ...
})
);
In questo modo, qualsiasi operazione normale relativa al prototype non viene persa.
Nel proxy ascolti l’accesso a qualsiasi proprietà tramite un getter. Il terzo argomento (receiver
) è l‘“oggetto”, in questo caso il numero stesso - lo chiami start
. È già del tipo giusto, number.
Il secondo argomento corrisponde al nome della proprietà, il suo typeof
è infatti string
.
Object.setPrototypeOf(
Number.prototype,
new Proxy(Number.prototype, {
get(_, _end, start) {
// _end -> '182' (typeof string)
// start -> 42 (typeof number)
}
})
)(42)[182];
È sufficiente utilizzare parseInt
e, se risulta ancora isNaN
, lanciare un errore/avviso. Oppure, puoi semplicemente ignorarlo silenziosamente e tornare a start
.
let end = parseInt(_end);
if (isNaN(end)) {
// warning se errore
// eventualmente, fallback
return start;
}
Assicurato che il typeof end
sia anch’esso number
, puoi procedere a generare il range.
return Array(end - start + 1)
.fill()
.map((_, i) => start + i);
La funzionalità di base è completa. Ora il seguente codice è perfettamente valido.
(0)[5]; // [0, 1, 2, 3, 4, 5]
To make it not-end-inclusive, use
Array(end - start)
instead ofArray(end - start + 1)
.
Range inverso
Per poter fare qualcosa di simile al seguente…
[5](0); // [5, 4, 3, 2, 1, 0]
Controlla se start > end
e, in tal caso, scambia entrambi. Non dimenticare di ordinare il risultato in ordine decrescente.
Il codice è autoesplicativo.
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]
Non avrei potuto fare la stessa cosa con una funzione range? Sì, probabilmente dovresti farlo con una funzione.
Lascia che questo sia un esercizio mentale e un modo per familiarizzare con il concetto di prototype e proxy.