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.
Per ricapitolare:
-
Se il risultato di un incremento/decremento non viene utilizzato, non ci sarà differenza qualsiasi forma venga utilizzata:
let counter = 0; counter++; ++counter; alert( counter ); // 2, le righe sopra fanno la stessa cosa -
Se lâintenzione è di incrementare il valore e utilizzare il valore, allora si utilizza la forma pre-fissa:
let counter = 0; alert( ++counter ); // 1 -
Se si ha intenzione di incrementare, ma utilizzare il valore precedente, allora sarà necessario utilizzare la forma post-fissa:
let counter = 0; alert( counter++ ); // 0
Gli operatori ++/-- possono essere utilizzati nello stesso modo allâinterno di un espressione. La loro precedenza sarà più alta rispetto alla maggioranza degli altri operatori aritmetici.
Ad esempio:
let counter = 1;
alert( 2 * ++counter ); // 4
Confrontatelo con:
let counter = 1;
alert( 2 * counter++ ); // 2, perché counter++ ritorna il "vecchio" valore
Sebbene sia tecnicamente permesso, questa sintassi rende il codice meno leggibile. Una linea che esegue più operazioni ++ non è mai un bene.
Mentre leggiamo il codice, una rapido scorrimento con lo sguardo in âverticaleâ può facilmente farci perdere una parte di codice, come ad esempio counter++, e potrebbe quindi non essere ovvio che la variabile incrementa.
Eâ consigliato utilizzare lo stile âuna linea â unâazioneâ:
let counter = 1;
alert( 2 * counter );
counter++;
Operatori sui bit
Gli operatori sui bit trattano gli argomenti come numeri interi rappresentati in 32-bit e lavorano sulla loro rappresentazione binaria.
Questi operatori non sono specifici di JavaScript, ma supportati in molti linguaggi di programmazione.
La lista degli operatori:
- AND (
&) - OR (
|) - XOR (
^) - NOT (
~) - LEFT SHIFT (
<<) - RIGHT SHIFT (
>>) - ZERO-FILL RIGHT SHIFT (
>>>)
Questi operatori vengono utilizzati molto raramente, quando abbiamo bisogno di lavorare con i numeri al più basso livello (bit per bit). Non avremo bisogno di questi operatori molto presto, poiché lo sviluppo web ne fa un uso limitato, ma in alcune aree speciali, come la crittografia, sono utili.In caso di necessità potete leggere lâarticolo operatori BitWise su MDN.
Virgola
Lâoperatore virgola , è uno degli operatori più rari ed inusuali. Qualche volta viene utilizzato per scrivere codice più breve, quindi è necessario capirlo bene per sapere cosa sta succedendo.
Lâoperatore virgola ci consente di valutare diverse espressioni, dividendole con ,. Ogni espressione viene valutata, ma viene restituito solo il risultato dellâultima.
Ad esempio:
let a = (1 + 2, 3 + 4);
alert( a ); // 7 (il risultato di 3 + 4)
Qui la prima espressione 1 + 2 viene valutata, ed il suo risultato viene scartato, successivamente viene eseguito 3 + 4 e il suo risultato viene restituito.
Lâoperatore virgola ha una precedenza molto bassa, più bassa di =, quindi le parentesi sono importanti nellâesempio sopra.
Senza parentesi: a = 1 + 2, 3 + 4 verrebbe valutato + prima, sommando i numeri in a = 3, 7, poi viene valutato lâoperatore di assegnazione = che assegna a = 3, e successivamente il numero 7 dopo la virgola, che viene ignorato.
Perché dovremmo avere bisogno di un operatore che non ritorna nulla tranne lâultima parte?
Qualche volta le persone lo utilizzano in costrutti più complessi che seguono più azioni in una sola riga.
Ad esempio:
// tre operazioni in un'unica riga
for (a = 1, b = 3, c = a * b; a < 10; a++) {
...
}
Questo âtrickâ viene utilizzato in molti framework JavaScript, per questo lâabbiamo menzionato. Ma solitamente non migliora la leggibilità del codice, quindi dovremmo pensarci bene prima di scrivere questo tipo di espressioni.
Commenti
<code>, per molte righe â includile nel tag<pre>, per più di 10 righe â utilizza una sandbox (plnkr, jsbin, codepenâ¦)