Molti operatori matematici già li conosciamo dalle scuole. Tra di essi ci sono l’addizione +, la moltiplicazione *, la sottrazione - e coì via.
In questo capitolo inizieremo con gli operatori semplici, quindi ci concentreremo sugli aspetti specifici di Javascript che non vengono trattati a scuola.
Termini: “unario”, “binario”, “operando”
Prima di iniziare, cerchiamo di capire la terminologia.
-
Un operando – è ciò a cui si applica l’operatore. Ad esempio nella moltiplicazione
5 * 2ci sono due operandi: l’operando sinistro è il numero5, e l’operando di destra è il numero2. A volte gli operandi vengo anche chiamati “argomenti”. -
Un operatore è unario se ha un singolo operando. Ad esempio, la negazione
-inverte il segno di un numero:let x = 1; x = -x; alert( x ); // -1, viene applicata la negazione unaria -
Un operatore è binario se ha due operandi. Lo stesso operatore “meno” esiste nella forma binaria:
let x = 1, y = 3; alert( y - x ); // 2, la sottrazione binaria sottrae i valoriFormalmente, negli esempi precedenti abbiamo due diversi operatori che condividono lo stesso simbolo: la negazione (operatore unario che inverte il segno) e la sottrazione (operatore binario che esegue la sottrazione).
Operatori matematici
Sono supportati seguenti operatori matematici:
- Addizione
+, - Sottrazione
-, - Moltiplicazione
*, - Divisione
/, - Resto
%, - Potenza
**.
I primi quattro sono piuttosto semplici, mentre % e ** richiedono qualche spiegazione.
Resto %
L’operatore resto %, diversamente da quello che si può pensare, non è legato alla percentuale.
Il risultato di a % b è il resto della divisione intera di a diviso b.
Ad esempio:
alert( 5 % 2 ); // 1, è il resto dell'operazione 5 diviso 2
alert( 8 % 3 ); // 2, è il resto dell'operazione 8 diviso 3
Elevamento a Potenza **
The exponentiation operator a ** b raises a to the power of b.
L’operatore di elevamento a potenza a ** b eleva a potenza a usando b come esponente.
In nomenclatura matematica viene scritto come ab.
Ad esempio:
alert( 2 ** 2 ); // 2² = 4
alert( 2 ** 3 ); // 2³ = 8
alert( 2 ** 4 ); // 2⁴ = 16
Come in matematica, l’esponente può essere anche un valore numerico non intero.
Ad esempio, la radice quadrata può essere vista come un elevamento a potenza con esponente 1/2:
alert( 4 ** (1/2) ); // 2 (potenza 1/2 equivale alla radice quadrata)
alert( 8 ** (1/3) ); // 2 (potenza 1/3 equivale alla radice cubica)
Concatenazione di stringhe, operatore binario +
Adesso diamo un’occhiata alle caratteristiche degli operatori in JavaScript, che vanno oltre l’aritmetica scolastica.
Solitamente l’operatore di somma + viene utilizzato per sommare due numeri.
Ma se l’operatore binario + viene applicato a delle stringhe, queste verranno unite (concatenate):
let s = "my" + "string";
alert(s); // mystring
Nota che se almeno uno degli operandi è una stringa, anche gli altri verranno convertiti in stringa.
Ad esempio:
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
Come puoi vedere, non è importante se la stringa è il primo il secondo operando. La regola è semplice: se uno degli operandi è una stringa, anche gli altri vengono convertiti a stringa.
Comunque, queste operazioni vengono eseguite da sinistra verso destra, Se ci sono due numeri prima di una stringa, prima vengono sommati e il risultato convertito in stringa:
Ora un esempio più complesso:
alert(2 + 2 + '1' ); // "41" non "221"
Qui le operazioni vengo eseguite una di seguito all’altra, da sinistra verso destra. Il primo + somma i due numeri e restituisce 4, quindi il successivo + concatena a quest’ultimo la stringa 1, quindi sarebbe come fare 4 + '1' = 41.
alert('1' + 2 + 2 ); // "122" non "14"
In questo esempio il primo operando è una stringa, quindi il compilatore tratterà anche i successivi operandi come stringhe. I 2 verranno concatenati alla stringa 1: '1' + 2 = 12 quindi '12' + 2 = '122'.
L’operatore binario + è l’unico che può lavorare con le stringhe in questo modo. Gli altri operatori aritmetici funzionano solo con i numeri. Infatti convertono sempre i loro operandi in numeri.
Questo è un esempio per la sottrazione e la divisione:
alert( 6 - '2' ); // 4, converte la stringa '2' in numero
alert( '6' / '2' ); // 3, converte entrambi gli operandi in numeri
Conversione numerica, operatore unario +
L’operatore + esiste in due forme. La forma binaria che abbiamo utilizzato sopra, e quella unaria.
L’operatore unario + viene applicato ad un singolo valore. Nel caso questo sia un numero, non succede nulla. Se invece non è un numero, questo viene convertito in un operando di tipo numerico.
Ad esempio:
// Nessun effetto sui numeri
let x = 1;
alert( +x ); // 1
let y = -2;
alert( +y ); // -2
// Converte i valori non numerici
alert( +true ); // 1
alert( +"" ); // 0
Si ottiene lo stesso risultato di Number(...), ma in un modo più veloce.
La necessità di convertire stringhe in numeri si presenta molto spesso. Ad esempio, se stiamo prelevando un valore da un campo HTML, questo solitamente sarà di tipo stringa. Come procedere in caso volessimo sommare questi valori?
La somma binaria li concatenerebbe come stringhe:
let apples = "2";
let oranges = "3";
alert( apples + oranges ); // "23", la somma binaria concatena le stringhe
Se vogliamo trattarli come numeri, dobbiamo prima convertirli e successivamente sommarli:
let apples = "2";
let oranges = "3";
// entrambi i valori vengono convertiti in numeri prima della somma binaria
alert( +apples + +oranges ); // 5
// la variante più lunga
// alert( Number(apples) + Number(oranges) ); // 5
Dal punto di vista di matematico l’abbondanza + può sembrare errato, ma dal punto di vista di un programmatore non c’e nulla di strano: i + unari vengono applicati per primi e si occupa di convertire le stringhe in numeri, successivamente il + binario esegue la somma.
Perché il + unario viene applicato prima di quello binario? Come adesso vedremo, questo accade per via della sua precedenza più alta.
Precedenza degli operatori
Se un espressione ha più di un operatore, l’ordine d’esecuzione viene definito dalla loro precedenza, in altre parole, c’è una priorità implicita tra gli operatori.
Fin dalle scuole sappiamo che la moltiplicazione nell’espressione 1 + 2 * 2 viene eseguita prima dell’addizione. E’ proprio questo che si intende con precedenza. La moltiplicazione sta dicendo di avere una precedenza più alta rispetto all’addizione.
Le parentesi, sovrascrivono qualsiasi precedenza, quindi se non siamo soddisfatti dell’ordine d’esecuzione, possiamo utilizzarle: (1 + 2) * 2.
Ci sono molti operatori in JavaScript. Ogni operatore ha un suo grado di precedenza. Quello con il grado più elevato viene eseguito per primo. Se il grado di precedenza è uguale, l’esecuzione andrà da sinistra a destra.
Un estratto della tabella delle precedenze (non è necessario che ve la ricordiate, ma tenete a mente che gli operatori unari hanno una precedenza più elevata rispetto ai corrispondenti binari):
| Precedence | Name | Sign |
|---|---|---|
| … | … | … |
| 17 | unary plus | + |
| 17 | unary negation | - |
| 16 | exponentiation | ** |
| 15 | multiplication | * |
| 15 | division | / |
| 13 | addition | + |
| 13 | subtraction | - |
| … | … | … |
| 3 | assignment | = |
| … | … | … |
Come possiamo vedere, la “somma unaria”(unary plus) ha una priorità di 17, che è maggiore del 13 dell’addizione(+ binario). Questo è il motivo per cui l’espressione "+apples + +oranges" esegue prima il + unario, e successivamente l’addizione.
Assegnazione
Da notare che anche l’assegnazione = è un operatore. Viene infatti elencato nella tabella delle precedenze con una priorità molto bassa: 3.
Questo è il motivo per cui quando assegniamo un valore ad una variabile, come x = 2 * 2 + 1, i calcoli vengono eseguiti per primi, e successivamente viene valutato l’operatore =, che memorizza il risultato in x.
let x = 2 * 2 + 1;
alert( x ); // 5
L’assegnazione = restituisce un valore
Il fatto che il simbolo = sia un operatore e non un costrutto “magico” del linguaggio, ha delle interessanti implicazioni.
Tutti gli operatori in Javascript restituiscono un valore. Questo è ovvio per + e -, ma è altrettanto vero per =.
La chiamata x = value scrive value in x e quindi lo restituisce.
Di seguito una dimostrazione di come usare un assegnamento come parte di una espressione pù complessa:
let a = 1;
let b = 2;
let c = 3 - (a = b + 1);
alert( a ); // 3
alert( c ); // 0
Nell’esempio qui sopra, il risultato dell l’espressione (a = b + 1) viene assegnato ad a (esso è 3). Quindi questo viene utilizzato per le successive valutazioni.
E’ un codice divertente, non trovate? Dovremmo sapere come funziona perché è possibile trovarlo in alcune librerie Javascript.
Comunque, per favore evitate di scrivere codice simile. Questo genere di scorciatoie rende il codice poco chiaro e leggibile.
Concatenare assegnazioni
Un’altra caratteristica interessante è l’abilità di concatenare assegnazioni:
let a, b, c;
a = b = c = 2 + 2;
alert( a ); // 4
alert( b ); // 4
alert( c ); // 4
Le assegnazioni concatenate vengono valutate da destra a sinistra. Prima viene valutata l’espressione più a destra 2 + 2 e successivamente viene valutata l’assegnazione a sinistra: c, b e a. Alla fine, tutte le variabili condivideranno lo stesso valore.
Ancora una volta, per favorire la leggibilità è meglio dividere il codice su più linee:
c = 2 + 2;
b = c;
a = c;
Questo è più facile da leggere, specialmente quando si scorre velocemente il codice.
Modifica sul posto
Spesso abbiamo bisogno di applicare un operatore ad una variabile ed assegnare il risultato alla variabile stessa.
Per esempio:
let n = 2;
n = n + 5;
n = n * 2;
Questa sintassi può essere abbreviata usando += and *=:
let n = 2;
n += 5; // ora n = 7 (equivale a n = n + 5)
n *= 2; // ura n = 14 (equivale a n = n * 2)
alert( n ); // 14
Gli operatori “modifica-e-assegna” esistono per tutti gli operatori matematici e sui bit: /=, -=, etc.
Questi operatori hanno la stessa precedenza delle normali assegnazioni, quindi vengono eseguiti dopo la maggior parte degli altri calcoli.
let n = 2;
n *= 3 + 5;
alert( n ); // 16 (prima viene valutata la parte destra, equivale a n *= 8)
## Incremento/Decremento
<!-- Can't use -- in title, because the built-in parser turns it into a 'long dash' – -->
L'incremento o il decremento di un numero di uno è una delle operazioni numeriche più comuni.
Quindi, ci sono speciali operatori dedicati a questo:
- **Incremento** `++` incrementa la variabile di 1:
```js run no-beautify
let counter = 2;
counter++; // sarebbe come fare counter = counter + 1, ma in maniera più breve
alert( counter ); // 3
```
- **Decremento** `--` decrementa la variabile di 1:
```js run no-beautify
let counter = 2;
counter--; // equivale a counter = counter - 1, ma è più breve da scrivere
alert( counter ); // 1
```
```warn
L'Incremento/decremento possono essere applicati solo a variabili. Se tentiamo di utilizzarli con un valore, come `5++` si otterrà un errore.
Gli operatori ++ e -- possono essere inseriti sia prima che dopo la variabile.
- Quando l’operatore viene messo dopo la variabile, viene detto “forma post-fissa”:
counter++. - La “forma pre-fissa” si ottiene inserendo l’operatore prima della variabile:
++counter.
Entrambi questi metodi portano allo stesso risultato: incrementano counter di 1.
C’è qualche differenza? Si, ma possiamo notarla solo se andiamo ad utilizzare il valore di ritorno di ++/--.
Facciamo chiarezza. Come sappiamo, tutti gli operatori restituiscono un valore. Incremento e decremento non fanno eccezione. La forma pre-fissa restituisce il nuovo valore, mentre la forma post-fissa restituisce il vecchio valore (prima dell’incremento/decremento).
Per vedere le differenze ecco un esempio:
let counter = 1;
let a = ++counter; // (*)
alert(a); // 2
Nella riga (*) la chiamata pre-fissa di ++counter incrementa counter e ritorna il nuovo valore che è 2. Quindi alert mostra 2.
Adesso proviamo ad utilizzare la forma post-fissa:
let counter = 1;
let a = counter++; // (*) abbiamo sostituito ++counter con counter++
alert(a); // 1
Nella riga (*) la forma post-fissa counter++ incrementa counter, ma ritorna il vecchio valore (prima dell’incremento). Quindi alert mostra 1