6. Le stringhe
Le stringhe di caratteri di JavaScript sono molto simili a quelle di PHP.

6.1. script [str-01]
La prima cosa da comprendere è che, una volta creata, una stringa non è più modificabile. Esistono numerosi metodi per generare una nuova stringa a partire da quella iniziale, ma quest’ultima rimane sempre invariata. Inoltre, una stringa di caratteri può essere di due tipi:
- [string] quando viene inizializzata con una stringa letterale;
- [object] quando viene creata come istanza della classe [String];
''use strict';
// le stringhe sono di sola lettura (non è possibile modificarle)
// una stringa
const chaîne1 = "abcd ";
// tipo
console.log("typeof(chaîne1)=", typeof (chaîne1));
// carattere n. 2
console.log("chaîne1[2]=", chaîne1[2]);
// genera un errore
chaîne1[2] = "0";
Esecuzione
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Temp\19-09-01\javascript\strings\str-01.js"
typeof(chaîne1)= string
chaîne1[2]= c
c:\Temp\19-09-01\javascript\strings\str-01.js:1
TypeError: Cannot assign to read only property '2' of string 'abcd '
at Object.<anonymous> (c:\Temp\19-09-01\javascript\strings\str-01.js:12:12)
at Generator.next (<anonymous>)
6.2. script [str-02]
Questo script mostra che è possibile costruire una stringa di caratteri in due modi.
''use strict';
// le stringhe possono essere di due tipi
// una stringa letterale
const chaîne1 = "abcd ";
// tipo
console.log("typeof(chaîne1)=", typeof (chaîne1));
// istanza di String
const chaîne2 = new String("xyzt");
// tipo
console.log("typeof(chaîne2)=", typeof (chaîne2));
// altra notazione (senza new) – tipo [string] e non [object]
const chaîne3 = String("12 34");
// tipo
console.log("typeof(chaîne3)=", typeof (chaîne3));
// il tipo [string] e il tipo [object] offrono gli stessi metodi, quelli della classe String
console.log("chaîne1.length=", chaîne1.length);
console.log("chaîne2.length=", chaîne2.length);
Commenti
- riga 6: il metodo usuale per definire una stringa. [chaîne1] sarà di tipo [string];
- riga 10: è possibile creare una stringa utilizzando il costruttore della classe [String]. [chaîne2] sarà di tipo [object];
Esecuzione
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\strings\str-02.js"
typeof(chaîne1)= string
typeof(chaîne2)= object
typeof(chaîne3)= string
chaîne1.length= 5
chaîne2.length= 4
Il tipo [string] beneficia dei metodi della classe [String].
6.3. script [str-03]
Questo script mostra una stringa specifica con interpolazione di variabili.
'use strict';
// stringa
const chaîne = "Introduction à Javascript par l'exemple";
// stringa con interpolazione di variabili
const str = `[${chaîne}].substr(3, 2)=` + chaîne.substr(3, 2)
console.log(str);
Commenti
- riga 6: è possibile avere stringhe contenenti espressioni ${variabile} che vengono sostituite dal valore della variabile. Si tratta della stessa logica delle variabili $ nelle stringhe PHP. Si noti la notazione di una stringa di questo tipo: è racchiusa tra «backstick» o apostrofo inverso (AltGr-7 su una tastiera francese);
Esecuzione
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Temp\19-09-01\javascript\strings\tempCodeRunnerFile.js"
[Introduction à Javascript par l'exemple].substr(3, 2)=ro
6.4. script [str-04]
La stringa con interpolazione delle variabili rimane insufficiente. Infatti, non è possibile sostituire la variabile con un’espressione all’interno dell’espressione ${variable}. Per chi ha programmato in C, non c’è nulla di paragonabile alle funzioni [printf, sprintf] per scrivere o costruire stringhe formattate. Centinaia di sviluppatori hanno creato migliaia di pacchetti JavaScript che formano un ecosistema immenso. Quando si ha un’esigenza che JavaScript non soddisfa in modo nativo, è il momento di cercare un pacchetto che la soddisfi. A tal fine utilizziamo il gestore di pacchetti [npm]. Quest’ultimo dispone di un’opzione [search] che consente di cercare una stringa di caratteri nella descrizione dei pacchetti. [npm] restituisce l’elenco dei pacchetti che soddisfano la ricerca. Cercheremo quindi la stringa [sprintf] nella descrizione dei pacchetti:

- nella colonna [4], le parole chiave dei pacchetti della colonna [3];
- nella colonna [5], la descrizione dei pacchetti della colonna [3];
Il passo successivo consiste nell’accedere al sito dello strumento [npm], [https://www.npmjs.com/] e leggere la descrizione dei pacchetti:

In [3], si esamina l’elenco dei pacchetti e se ne sceglie uno.

Nella descrizione del pacchetto si trovano le informazioni per installarlo e utilizzarlo:

Installiamo il pacchetto [sprintf-js] in un terminale di [VSCode]:

Questa installazione modificherà il file [package.json] situato nella directory principale di [javascript] [2]:

Come si vede sopra, il pacchetto è stato installato in [dependencies], ovvero nei pacchetti necessari all’esecuzione del progetto. Si ricorda che i pacchetti necessari vengono inseriti in [devDependencies] solo durante lo sviluppo del progetto. Non vengono utilizzati durante l’esecuzione. Questa differenza è importante quando si deve creare la versione finale del progetto per la sua messa in produzione. Esistono strumenti per:
- raggruppare tutti i file jS necessari all’esecuzione in un unico file. I pacchetti [devDependencies] non sono quindi inclusi in questo file finale;
- minimizzarlo, ovvero ridurne le dimensioni il più possibile. A tal fine, ad esempio, vengono eliminati tutti i commenti;
- «oscurare» il codice per renderlo di difficile comprensione. Ad esempio, le variabili tasso, stipendio, imposta saranno sostituite dalle variabili a, b, c;
- effettuare altre ottimizzazioni;
Questa ottimizzazione del file finale di un progetto jS viene utilizzata nella programmazione web. Un’applicazione web può dipendere da un numero molto elevato di file JavaScript. Il loro caricamento da parte di un browser può rallentare la visualizzazione della prima pagina dell’applicazione. L’ottimizzazione precedente mira a migliorare questo tempo di caricamento. Se il tempo di caricamento viene ritenuto troppo lungo dagli utenti, l’applicazione non verrà utilizzata.
Ora che disponiamo del pacchetto [sprintf-js], dobbiamo utilizzarlo. Si tratta dello script [str-04]:
'use strict';
// utilizzo di un pacchetto esterno per disporre della funzione sprintf
import { sprintf } from 'sprintf-js';
// stringa
const chaîne = "Introduction à Javascript par l'exemple";
// metodo
console.log(sprintf("[%s].substr(3,2)=[%s]", chaîne, chaîne.substr(3, 2)));
Con ECMAScript 6, si utilizza la parola chiave [import] per importare un oggetto esportato da un pacchetto. Per sapere cosa esporta il pacchetto, è possibile consultare il suo codice:

- in [1], clic destro sul pacchetto importato;
- in [2], si desidera visualizzarne la definizione;
- in [3-4], si vede che il pacchetto esporta una funzione denominata [sprintf];
La funzione [sprintf] del pacchetto [sprintf-js] viene importata con l'istruzione:
import { sprintf } from 'sprintf-js';
Il codice completo:
'use strict';
// utilizzo di un pacchetto esterno per disporre della funzione sprintf
import { sprintf } from 'sprintf-js';
// stringa
const chaîne = "Introduction à Javascript par l'exemple";
// metodo
console.log(sprintf("[%s].substr(3,2)=[%s]", chaîne, chaîne.substr(3, 2)));
produce i seguenti risultati:
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\strings\str-04.js"
c:\Temp\19-09-01\javascript\strings\str-04.js:3
import { sprintf } from 'sprintf-js';
^
SyntaxError: Unexpected token {
at new Script (vm.js:79:7)
at createScript (vm.js:251:10)
at Object.runInThisContext (vm.js:303:10)
at Module._compile (internal/modules/cjs/loader.js:657:28)
Riga 3: l'istruzione [import] non è stata compresa. Ciò è dovuto al fatto che la versione 10.15.1 di [node.js] utilizzata in questo corso (settembre 2019) non rispetta ancora lo standard ECMAScript per l’importazione di pacchetti denominati moduli. Nel 2019, [node.js] rispetta uno standard di moduli denominato CommonJS. L’integrazione dei moduli ECMAScript da parte di [node.js] è prevista per il 2020. Anche in questo caso, alcuni sviluppatori si sono messi all’opera e hanno realizzato pacchetti che consentono di utilizzare i moduli ES6 con [node.js] già da ora (2019).
Utilizzeremo un pacchetto denominato [esm] (Moduli ECMAScript). Lo installiamo in un terminale del progetto [javascript]:

In [4], si nota che l’installazione del pacchetto [esm] [1-3] ha modificato il file [javascript/package.json].
Ma non è tutto. Affinché il modulo [esm] venga utilizzato da [node.js], è necessario avviare quest’ultimo con l’argomento [-r esm].
Modifichiamo quindi la configurazione dell’estensione [Code Runner] di [VSCode]:


In [11], aggiungiamo l’argomento [-r esm] e salviamo (Ctrl-S) la configurazione.
Ora possiamo eseguire lo script [str-04]:
'use strict';
// utilizzo di un pacchetto esterno per disporre della funzione sprintf
import { sprintf } from 'sprintf-js';
// stringa
const chaîne = "Introduction à Javascript par l'exemple";
// metodo substr
console.log(sprintf("[%s].substr(3,2)=[%s]", chaîne, chaîne.substr(3, 2)));

6.5. script [str-05]
Ecco cosa dice la documentazione sulla funzione [sprintf]:
I segnaposto nella stringa di formato sono contrassegnati dal simbolo % e sono seguiti da uno o più di questi elementi, in questo ordine:
- Un numero facoltativo seguito dal segno $ che seleziona l’indice dell’argomento da utilizzare per il valore. Se non specificato, gli argomenti saranno disposti nello stesso ordine dei segnaposto nella stringa di input.
- Un segno + opzionale che impone di anteporre al risultato un segno più o meno sui valori numerici. Per impostazione predefinita, sui numeri negativi viene utilizzato solo il segno -.
- Uno specificatore di riempimento opzionale che indica quale carattere utilizzare per il riempimento (se specificato). I valori possibili sono 0 o qualsiasi altro carattere preceduto da un ' (apice singola). Per impostazione predefinita, il riempimento avviene con spazi.
- Un segno - opzionale, che fa sì che sprintf allinei a sinistra il risultato di questo segnaposto. Per impostazione predefinita, il risultato viene allineato a destra.
- Un numero opzionale che indica quanti caratteri deve avere il risultato. Se il valore da restituire è più breve di questo numero, il risultato verrà riempito. Se utilizzato con il specificatore di tipo j (JSON), la lunghezza di riempimento specifica la dimensione del tabulatore utilizzata per l'indentazione.
- Un modificatore di precisione opzionale, costituito da un . (punto) seguito da un numero, che indica quante cifre devono essere visualizzate per i numeri in virgola mobile. Se utilizzato con il specificatore di tipo g, specifica il numero di cifre significative. Se utilizzato su una stringa, provoca il troncamento del risultato.
- Un specificatore di tipo che può assumere uno dei seguenti valori:
- % — restituisce il carattere letterale %
- b — restituisce un numero intero come numero binario
- c — restituisce un numero intero come carattere con quel valore ASCII
- d o i — restituisce un numero intero come numero decimale con segno
- e — restituisce un numero in virgola mobile in notazione scientifica
- u — restituisce un numero intero come numero decimale senza segno
- f — restituisce un valore float così com’è; si vedano le note sulla precisione riportate sopra
- g — restituisce un valore float così com'è; si vedano le note sulla precisione riportate sopra
- o — restituisce un numero intero in formato ottale
- s — restituisce una stringa così com'è
- t — restituisce true o false
- T — restituisce il tipo dell'argomento1
- v — restituisce il valore primitivo dell'argomento specificato
- x — restituisce un numero intero in formato esadecimale (minuscolo)
- X — restituisce un numero intero come numero esadecimale (in maiuscolo)
- j — restituisce un oggetto o un array JavaScript come stringa codificata in formato JSON
Lo script [script-05] implementa alcuni di questi formati:
'use strict';
// utilizzo di un pacchetto esterno per disporre della funzione sprintf
import { sprintf } from 'sprintf-js';
// stringa
const chaîne = "Javascript";
// stringhe di caratteri
console.log(sprintf("[%s, %%s]=>[%s]", chaîne, chaîne));
console.log(sprintf("[%s, %%20s]=>[%20s]", chaîne, chaîne));
console.log(sprintf("[%s, %%-20s]=>[%-20s]", chaîne, chaîne));
// interi
console.log(sprintf("[%d, %%d]=>[%d]", 10, 10));
console.log(sprintf("[%d, %%4d]=>[%4d]", 10, 10));
console.log(sprintf("[%d, %%-4d]=>[%-4d]", 10, 10));
console.log(sprintf("[%d, %%04d]=>[%04d]", 10, 10));
// numeri reali
console.log(sprintf("[%f, %%f]=>[%f]", -10.5, -10.5));
console.log(sprintf("[%f, %%10.2f]=>[%10.2f]", -10.5, -10.5));
console.log(sprintf("[%f, %%-10.2f]=>[%-10.2f]", -10.5, -10.5));
console.log(sprintf("[%f, %%010.3f]=>[%010.3f]", -10.5, -10.5));
// json
console.log(sprintf("personne (%%j)=%j", { nom: "mathieu", âge: 34 }));
// tipo
console.log(sprintf("type personne (%%T)=%T", { nom: "mathieu", âge: 34 }));
// booleano
console.log(sprintf("booléen (%%t)=%t", 4 === 4));
Esecuzione
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\strings\str-05.js"
[Javascript, %s]=>[Javascript]
[Javascript, %20s]=>[ Javascript]
[Javascript, %-20s]=>[Javascript ]
[10, %d]=>[10]
[10, %4d]=>[ 10]
[10, %-4d]=>[10 ]
[10, %04d]=>[0010]
[-10.5, %f]=>[-10.5]
[-10.5, %10.2f]=>[ -10.50]
[-10.5, %-10.2f]=>[-10.50 ]
[-10.5, %010.3f]=>[-00010.500]
personne (%j)={"nom":"mathieu","âge":34}
type personne (%T)=object
booléen (%t)=true
6.6. script [str-06]
Lo script [str-06] presenta alcuni metodi della classe [String] utilizzabili anche sul tipo [string]:
'use strict';
// utilizzo di un pacchetto esterno per disporre della funzione sprintf
import { sprintf } from 'sprintf-js';
// stringa
const chaîne = " Introduction à Javascript ";
// alcuni metodi
// substr(10,2): 2 caratteri a partire dal n. 10
console.log(sprintf("[%s].substr(10,2)=[%s]", chaîne, chaîne.substr(10, 2)));
// trim: rimozione degli spazi all'inizio e alla fine della stringa (spazio=\b \t \r \n \f)
console.log(sprintf("[%s].trim()=[%s]", chaîne, chaîne.trim()));
// toLowerCase: conversione in minuscolo
console.log(sprintf("[%s].toLowerCase=[%s]", chaîne, chaîne.toLowerCase()));
// toUpperCase: conversione in maiuscolo
console.log(sprintf("[%s].toUpperCase=[%s]", chaîne, chaîne.toUpperCase()));
// indexOf: posizione di una string a ricercata nella stringa, -1 se la sottostringa non esiste
console.log(sprintf("[%s].indexOf('Java')=[%s]", chaîne, chaîne.indexOf('Java')));
console.log(sprintf("[%s].trim().indexOf('abcd')=[%s]", chaîne, chaîne.indexOf('abcd')));
// includes: vero se la stringa cercata è presente nella stringa
console.log(sprintf("[%s].includes('Java')=[%s]", chaîne, chaîne.includes('Java')));
// length: lunghezza della stringa - non è un metodo ma una proprietà
console.log(sprintf("[%s].length=[%s]", chaîne, chaîne.length));
// slice (7,10): stringa composta dai caratteri dal n. 7 al n. 9
console.log(sprintf("[%s].slice(7,10)=[%s]", chaîne, chaîne.slice(7, 10)));
// match: cerca un'espressione nella stringa - tale espressione può essere un'espressione regolare
// /intro/i: espressione regolare che indica la stringa [intro] in maiuscolo o minuscolo
// restituisce la stringa trovata
console.log(sprintf("[%s].match(/intro/i)=[%s]", chaîne, chaîne.match(/intro/i)));
// sostituisci: sostituisce stringa1 con stringa2 nella stringa
// sostituisce la prima occorrenza di i con x
console.log(sprintf("[%s].replace('i','x')=[%s]", chaîne, chaîne.replace('i', 'x')));
// sostituisce tutte le occorrenze di i con x
// /i/g è un'espressione regolare che indica tutte (g) le occorrenze di i
console.log(sprintf("[%s].replace(/i/g,'x')=[%s]", chaîne, chaîne.replace(/i/g, 'x')));
// split: divide la stringa in parole separate dal parametro di divisione
// restituisce l'array di queste parole
// /\s*/: parole separate da zero o più spazi
console.log(sprintf("[%s].split(/\\s*/)=[%s]", chaîne, chaîne.split(/\s*/)));
// /\s+/: parole separate da uno o più spazi
console.log(sprintf("[%s].split(/\\s+/)=[%s]", chaîne, chaîne.split(/\s+/)));
Esecuzione
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\strings\str-06.js"
[ Introduction à Javascript ].substr(10,2)=[ti]
[ Introduction à Javascript ].trim()=[Introduction à Javascript]
[ Introduction à Javascript ].toLowerCase=[ introduction à javascript ]
[ Introduction à Javascript ].toUpperCase=[ INTRODUCTION À JAVASCRIPT ]
[ Introduction à Javascript ].indexOf('Java')=[17]
[ Introduction à Javascript ].trim().indexOf('abcd')=[-1]
[ Introduction à Javascript ].includes('Java')=[true]
[ Introduction à Javascript ].length=[28]
[ Introduction à Javascript ].slice(7,10)=[duc]
[ Introduction à Javascript ].match(/intro/i)=[Intro]
[ Introduction à Javascript ].replace('i','x')=[ Introductxon à Javascript ]
[ Introduction à Javascript ].replace(/i/g,'x')=[ Introductxon à Javascrxpt ]
[ Introduction à Javascript ].split(/\s*/)=[,I,n,t,r,o,d,u,c,t,i,o,n,à,J,a,v,a,s,c,r,i,p,t,]
[ Introduction à Javascript ].split(/\s+/)=[,Introduction,à,Javascript,]