Skip to content

3. Le basi di JavaScript

Nota: nel prosieguo, il termine [Javascript] indicherà sempre lo standard ECMAScript 6.

All’interno del progetto JavaScript precedente, create una cartella [bases]. Vi inseriremo gli esempi di questa sezione:

Image

3.1. script [bases-01]

Per introdurre le basi di PHP7, avevamo utilizzato il seguente codice (cfr. paragrafo «link»):


<?php

// questo è un commento
// variabile utilizzata senza essere stata dichiarata
$nom = "dupont";
// un messaggio a schermo
print "nom=$nom\n";
// un array con elementi di tipo diverso
$tableau = array("un", "deux", 3, 4);
// il numero dei suoi elementi
$n = count($tableau);
// un ciclo
for ($i = 0; $i < $n; $i++) {
  print "tableau[$i]=$tableau[$i]\n";
}
// inizializzazione di 2 variabili con il contenuto di un array
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// concatenazione delle 2 stringhe
$chaine3 = $chaine1 . $chaine2;
// visualizzazione del risultato
print "[$chaine1,$chaine2,$chaine3]\n";
// utilizzo di una funzione
affiche($chaine1);
// il tipo di una variabile può essere noto
afficheType("n", $n);
afficheType("chaine1", $chaine1);
afficheType("tableau", $tableau);
// il tipo di una variabile può cambiare durante l'esecuzione
$n = "a changé";
afficheType("n", $n);
// una funzione può restituire un risultato
$res1 = f1(4);
print "res1=$res1\n";
// una funzione può restituire un array di valori
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// si sarebbero potuti recuperare questi valori in un array
$t = f2();
for ($i = 0; $i < count($t); $i++) {
  print "t[$i]=$t[$i]\n";
}
// test
for ($i = 0; $i < count($t); $i++) {
  // visualizza solo le stringhe
  if (getType($t[$i]) === "string") {
    print "t[$i]=$t[$i]\n";
  }
}
// operatori di confronto == e ===
if("2"==2){
  print "avec l'opérateur ==, la chaîne 2 est égale à l'entier 2\n";
}else{
  print "avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2\n";
}
if("2"===2){
  print "avec l'opérateur ===, la chaîne 2 est égale à l'entier 2\n";
}
else{
  print "avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2\n";
}
// altri test
for ($i = 0; $i < count($t); $i++) {
  // visualizza solo i numeri interi >10
  if (getType($t[$i]) === "integer" and $t[$i] > 10) {
    print "t[$i]=$t[$i]\n";
  }
}
// un ciclo while
$t = [8, 5, 0, -2, 3, 4];
$i = 0;
$somme = 0;
while ($i < count($t) and $t[$i] > 0) {
  print "t[$i]=$t[$i]\n";
  $somme += $t[$i];   //$somme=$somme+$t[$i]
  $i++;               //$i=$i+1
}//mentre
print "somme=$somme\n";

// fine programma
exit;

//----------------------------------
function affiche($chaine) {
  // visualizza $chaine
  print "chaine=$chaine\n";
}

//visualizza
//----------------------------------
function afficheType($name, $variable) {
  // visualizza il tipo di $variable
  print "type[variable $" . $name . "]=" . getType($variable) . "\n";
}

//afficheType
//----------------------------------
function f1($param) {
  // aggiunge 10 a $param
  return $param + 10;
}

//----------------------------------
function f2() {
  // restituisce 3 valori
  return array("un", 0, 100);
}
?>

Tradotto in JavaScript, si ottiene il seguente codice:


'use strict';
// questo è un commento
// costante
const nom = "dupont";
// un messaggio a schermo
console.log("nom : ", nom);
// un array con elementi di tipo diverso
const tableau = ["un", "deux", 3, 4];
// il numero dei suoi elementi
let n = tableau.length;
// un ciclo
for (let i = 0; i < n; i++) {
  console.log("tableau[", i, "] = ", tableau[i]);
}
// inizializzazione di 2 variabili con il contenuto di un array
let [chaine1, chaine2] = ["chaine1", "chaine2"];
// concatenazione delle 2 stringhe
const chaine3 = chaine1 + chaine2;
// visualizzazione del risultato
console.log([chaine1, chaine2, chaine3]);
// utilizzo di una funzione
affiche(chaine1);
// il tipo di una variabile può essere noto
afficheType("n", n);
afficheType("chaine1", chaine1);
afficheType("tableau", tableau);
// il tipo di una variabile può cambiare durante l'esecuzione
n = "a changé";
afficheType("n", n);
// una funzione può restituire un risultato
let res1 = f1(4);
console.log("res1=", res1);
// una funzione può restituire un array di valori
let res2, res3;
[res1, res2, res3] = f2();
console.log("(res1,res2,res3)=", [res1, res2, res3]);
// si sarebbero potuti recuperare questi valori in un array
let t = f2();
for (let i = 0; i < t.length; i++) {
  console.log("t[i]=", t[i]);
}
// test
for (let i = 0; i < t.length; i++) {
  // visualizza solo le stringhe
  if (typeof (t[i]) === "string") {
    console.log("t[i]=", t[i]);
  }
}
// operatori di confronto == e ===
if ("2" == 2) {
  console.log("avec l'opérateur ==, la chaîne 2 est égale à l'entier 2");
} else {
  console.log("avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2");
}
if ("2" === 2) {
  console.log("avec l'opérateur ===, la chaîne 2 est égale à l'entier 2");
} else {
  console.log("avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2");
}
// altri test
for (let i = 0; i < t.length; i++) {
  // visualizza solo i numeri interi maggiori di 10
  if (typeof (t[i]) === "number" && Math.floor(t[i]) === t[i] && t[i] > 10) {
    console.log("t[i]=", t[i]);
  }
}
// un ciclo while
t = [8, 5, 0, -2, 3, 4];
let i = 0;
let somme = 0;
while (i < t.length && t[i] > 0) {
  console.log("t[i]=", t[i]);
  somme += t[i];
  i++;
}
console.log("somme=", somme);

// il programma si interrompe perché non c'è più codice eseguibile

//visualizza
//----------------------------------
function affiche(chaine) {
  // visualizza una stringa
  console.log("chaine=", chaine);
}

//afficheType
//----------------------------------
function afficheType(name, variable) {
  // visualizza il tipo di variabile
  console.log("type[variable ", name, "]=", typeof (variable));
}

//----------------------------------
function f1(param) {
  // aggiunge 10 al parametro
  return param + 10;
}

//----------------------------------
function f2() {
  // restituisce 3 valori
  return ["un", 0, 100];
}

Commentiamo le differenze tra i codici PHP e ECMAScript 6 con la dichiarazione [use strict] (riga 1):

  • la prima differenza è che in ECMAScript le variabili vengono dichiarate con le seguenti parole chiave:
    • [let] per dichiarare una variabile il cui valore può cambiare durante l’esecuzione del codice;
    • [const] per dichiarare una variabile il cui valore non cambierà (quindi una costante) durante l’esecuzione del codice;
    • è anche possibile utilizzare la parola chiave [var] al posto di [let]. Era la parola chiave utilizzata con ECMAScript 5. Non la useremo in questo corso;
  • riga 6: il metodo di visualizzazione [console.log] è in grado di visualizzare ogni tipo di dato: stringhe, numeri, valori booleani, array, oggetti. Il metodo PHP [print] non è in grado di visualizzare in modo nativo array e oggetti. Nell’espressione [console.log], [console] è un oggetto e [log] è un metodo di tale oggetto;
  • riga 8: gli array JavaScript sono oggetti a cui si fa riferimento tramite un puntatore. Quando si scrive:

const tableau = ["un", "deux", 3, 4];

la variabile [tableau] è un puntatore all'array letterale ["un", "deux", 3, 4]. Modificare il contenuto dell'array non modifica il suo puntatore. Pertanto, un array verrà dichiarato il più delle volte con la parola chiave [const]. In PHP, un array non è referenziato da un puntatore. Si tratta di un dato letterale;

  • riga 12: la variabile di ciclo [i] viene dichiarata (let) all’interno del ciclo. La parola chiave [let] rispetta l’ambito del blocco (codice tra parentesi graffe). Pertanto, la variabile [i] della riga 12 è nota solo all’interno del ciclo;
  • riga 18: l’operatore di concatenazione delle stringhe è l’operatore + in JavaScript, . in PHP. Una particolarità di questo operatore è che ha precedenza sull’operatore + di addizione. Pertanto:
    • in PHP, ‘1’ +2 dà il numero 3;
    • in JavaScript ‘1’+2 restituisce la stringa ‘12’;
  • riga 20: [console.log] è in grado di visualizzare tabelle;
  • riga 82: in JavaScript non è possibile specificare il tipo dei parametri di una funzione;
  • riga 91: l’operatore [typeof] permette di determinare il tipo di un dato. Ce ne sono quattro: numero, stringa, booleano e oggetto. Si noti che in JavaScript non esistono né il tipo [integer] né il tipo [tableau]. Come già detto, gli array vengono gestiti tramite puntatori e rientrano nella categoria degli oggetti;
  • righe 50-59: come in PHP, JavaScript dispone di due operatori di confronto, == e ‘===’, con lo stesso significato che in PHP. ESLint segnala molto spesso l’operatore == come possibile errore. Si utilizzerà sistematicamente l’operatore ‘===’;
  • riga 79: si sarebbe potuto inserire l'istruzione [return], ma ESLint genera l'avviso che [return] deve essere utilizzato solo all'interno di una funzione;

Eseguiamo questo codice:

Image

Risultati dell’esecuzione:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-01.js"
nom : dupont
tableau[ 0 ] = un
tableau[ 1 ] = deux
tableau[ 2 ] = 3
tableau[ 3 ] = 4
[ 'chaine1', 'chaine2', 'chaine1chaine2' ]
chaine= chaine1
type[variable n ]= number
type[variable chaine1 ]= string
type[variable tableau ]= object
type[variable n ]= string
res1= 14
(res1,res2,res3)= [ 'un', 0, 100 ]
t[ 0 ]= un
t[ 1 ]= 0
t[ 2 ]= 100
t[ 0 ]= un
avec l'opérateur ==, la chaîne 2 est égale à l'entier 2
avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2
t[ 2 ]= 100
t[ 0 ]= 8
t[ 1 ]= 5
somme= 13

[Done] exited with code=0 in 0.316 seconds

Nel codice scritto, ESLINT segnala due errori:

Image

  • passando il cursore sulla riga rossa dell’avviso, compare il messaggio di errore [3]. In questo caso, ESLint non riconosce che si stanno confrontando due costanti. Uno dei due operandi dovrebbe essere una variabile;
  • in [4], un’opzione [Quick Fix] consente di eliminare l’avviso se si decide di non correggere l’errore;

Image

  • in [5], è possibile disattivare l'avviso per la riga corrente o per l'intero file. In questo caso scegliamo quest'ultima opzione. Viene quindi generata la riga [6] all'inizio del file;

3.2. script [bases-02]

Lo script [bases-02] mostra l’utilizzo delle parole chiave [let] e [const]:


'use strict';
// per inizializzare una variabile, si usa let o const
// let per le variabili
let x = 4;
x++;
console.log(x);
// const per le costanti
const y = 10;
x += y;
// vietato
y++;
  • la riga 11 genera un errore durante l'esecuzione di [1-2]. L'errore viene segnalato da ESLint prima dell'esecuzione di [3]:

Image

3.3. script [bases-03]

Lo script [bases-03] esamina l’ambito delle variabili in JavaScript:


'use strict';
// ambito delle variabili
let count = 1;
function doSomething() {
  // count è qui definito
  console.log("count=",count);
}
// chiamata
doSomething();
  • la variabile [count] dichiarata al di fuori della funzione [doSomething] è tuttavia riconosciuta all’interno di tale funzione. Si tratta di una differenza fondamentale rispetto a PHP;

Esecuzione


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-03.js"
count= 1

[Done] exited with code=0 in 0.3 seconds

3.4. script [bases-04]

Una variabile locale nasconde una variabile globale con lo stesso nome:


'use strict';
// ambito delle variabili
const count = 1;
function doSomething() {
  // la variabile locale nasconde la variabile globale
  const count = 2;
  console.log("count inside function=",count);
}
// variabile globale
console.log("count outside function=",count);
// variabile locale
doSomething();

Esecuzione


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-04.js"
count outside function= 1
count inside function= 2

[Done] exited with code=0 in 0.246 seconds

3.5. script [bases-05]

Una variabile definita all'interno di una funzione non è visibile al di fuori di essa:


'use strict';
// ambito delle variabili
function doSomething() {
  // variabile locale della funzione
  const count = 2;
  console.log("count inside function=", count);
}
// qui count non è definito
console.log("count outside function=", count);
doSomething();

ESLint segnala un errore alla riga 9:

Image

3.6. script [bases-06]

Le parole chiave [let] e [const] definiscono variabili nell'ambito [bloc] (codice tra parentesi graffe), ma non la parola chiave [var]:


'use strict';
// la parola chiave [let] consente di definire una variabile con ambito di blocco
{
  // la variabile [count] è nota solo in questo blocco
  let count = 1;
  console.log("count=", count);
}
// qui la variabile [count] non è riconosciuta
count++;

// la parola chiave [const] consente di definire una variabile con ambito di blocco
{
  // la variabile [count2] è nota solo in questo blocco
  const count2 = 1;
  console.log("count=", count2);
}
// qui la variabile [count2] non è conosciuta
count2++;

// la parola chiave [var] non consente di definire una variabile con ambito di blocco
{
  // la variabile [count3] sarà nota a livello globale
  var count3 = 1;
  console.log("count=", count3);
}
// qui la variabile [count3] è nota
count3++;

Commenti

  • riga 5: la variabile [count] è valida solo all’interno del blocco di codice in cui è dichiarata (righe 3-7);
  • riga 14: la costante [count2] è valida solo all’interno del blocco di codice in cui è dichiarata (righe 12-16);
  • riga 23: la variabile [count3] è nota al di fuori del blocco di codice in cui è dichiarata (righe 21-25);

ESLint segnala i seguenti errori:

Image

Per questi motivi legati all’ambito del blocco, d’ora in poi useremo solo le parole chiave [let] e [const].

3.7. script [bases-07]

I tipi di dati in JavaScript:


'use strict';

// tipo di dati jS
const var1 = 10;
const var2 = "abc";
const var3 = true;
const var4 = [1, 2, 3];
const var5 = {
  nom: 'axèle'
};
const var6 = function () {
  return +3;
}
// visualizzazione dei tipi
console.log("typeof(var1)=", typeof (var1));
console.log("typeof(var2)=", typeof (var2));
console.log("typeof(var3)=", typeof (var3));
console.log("typeof(var4)=", typeof (var4));
console.log("typeof(var5)=", typeof (var5));
console.log("typeof(var6)=", typeof (var6));

Esecuzione


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-07.js"
typeof(var1)= number
typeof(var2)= string
typeof(var3)= boolean
typeof(var4)= object
typeof(var5)= object
typeof(var6)= function

[Done] exited with code=0 in 0.26 seconds

Commenti

  • riga 7 (codice): un array è un oggetto. In quanto tale, [var4] è un puntatore all'array, non l'array stesso;
  • riga 8 (codice): [var5] è un puntatore a un oggetto letterale. Vedremo che gli oggetti letterali di JavaScript assomigliano molto alle istanze di classe di PHP. Anche questi sono referenziati tramite puntatori;
  • riga 11 (codice): una variabile può essere di tipo [fonction] (riga 7 dei risultati);

3.8. script [bases-08]

Questo script mostra i possibili cambiamenti di tipo in JavaScript.


'use strict';

// conversioni implicite di tipo
// tipo --> bool
console.log("---------------[Conversion implicite vers un booléen]------------------------------");
showBool("abcd");
showBool("");
showBool([1, 2, 3]);
showBool([]);
showBool(null);
showBool(0.0);
showBool(0);
showBool(4.6);
showBool({});
showBool(undefined);

function showBool(data) {
  // la conversione da data a booleano avviene automaticamente nel test successivo
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[valeur booléenne(data)]=", data ? true : false);
}

// conversioni implicite di tipo  verso un tipo numerico
console.log("---------------[Conversion implicite vers un nombre]------------------------------");
showNumber("12");
showNumber("45.67");
showNumber("abcd");

function showNumber(data) {
  // data + 1 non funziona perché in tal caso jS esegue una concatenazione di stringhe anziché un'addizione
  const nombre = data * 1;
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[nombre]=", nombre, "[type(nombre)]=", typeof (nombre));
}

// conversioni esplicite da altri tipi a un valore booleano
console.log("---------------[Conversion explicite vers un booléen]------------------------------");
showBool2("abcd");
showBool2("");
showBool2([1, 2, 3]);
showBool2([]);
showBool2(null);
showBool2(0.0);
showBool2(0);
showBool2(4.6);
showBool2({});
showBool2(undefined);

function showBool2(data) {
  // la conversione di data in booleano avviene esplicitamente nel test che segue
  console.log("[", data, "], [type(data)]=", typeof (data), "[valeur booléenne(data)]=", Boolean(data));
}
// conversioni esplicite in tipo Number
console.log("---------------[Conversion explicite vers un nombre]------------------------------");
showNumber2("12.45");
showNumber2(67.8);
showNumber2(true);
showNumber2(null);

function showNumber2(data) {
  const nombre = Number(data);
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[nombre]=", nombre, "[type(nombre)]=", typeof (nombre));
}

// verso String
console.log("---------------[Conversion explicite vers un string]------------------------------");
showString(5);
showString(6.7);
showString(false);
showString(null);

function showString(data) {
  const chaîne = String(data);
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[chaîne]=", chaîne, "[type(chaîne)]=", typeof (chaîne));
}

// alcune conversioni implicite inattese
console.log("---------------[Autres cas]------------------------------");
const string1 = '1000.78';
// concatenazione di stringhe per impostazione predefinita
const data1 = string1 + 1.034;
console.log("data1=", data1, "type=", typeof (data1));
const data2 = 1.034 + string1;
console.log("data2=", data2, "type=", typeof (data2));
// conversione esplicita in numero
const data3 = Number(string1) + 1.034;
console.log("data3=", data3, "type=", typeof (data3));
// true viene convertito nel numero 1
const data4 = true * 1.18;
console.log("data4=", data4, "type=", typeof (data4));
// false viene convertito nel numero 0
const data5 = false * 1.18;
console.log("data5=", data5, "type=", typeof (data5));

Esecuzione


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Data\st-2019\dev\es6\javascript\bases\bases-08.js"
---------------[Conversion implicite vers un booléen]------------------------------
[data= abcd ], [type(data)]= string [valeur booléenne(data)]= true
[data= ], [type(data)]= string [valeur booléenne(data)]= false
[data= [ 1, 2, 3 ] ], [type(data)]= object [valeur booléenne(data)]= true
[data= [] ], [type(data)]= object [valeur booléenne(data)]= true
[data= null ], [type(data)]= object [valeur booléenne(data)]= false
[data= 0 ], [type(data)]= number [valeur booléenne(data)]= false
[data= 0 ], [type(data)]= number [valeur booléenne(data)]= false
[data= 4.6 ], [type(data)]= number [valeur booléenne(data)]= true
[data= {} ], [type(data)]= object [valeur booléenne(data)]= true
[data= undefined ], [type(data)]= undefined [valeur booléenne(data)]= false
---------------[Conversion implicite vers un nombre]------------------------------
[data= 12 ], [type(data)]= string [nombre]= 12 [type(nombre)]= number
[data= 45.67 ], [type(data)]= string [nombre]= 45.67 [type(nombre)]= number
[data= abcd ], [type(data)]= string [nombre]= NaN [type(nombre)]= number
---------------[Conversion explicite vers un booléen]------------------------------
[ abcd ], [type(data)]= string [valeur booléenne(data)]= true
[ ], [type(data)]= string [valeur booléenne(data)]= false
[ [ 1, 2, 3 ] ], [type(data)]= object [valeur booléenne(data)]= true
[ [] ], [type(data)]= object [valeur booléenne(data)]= true
[ null ], [type(data)]= object [valeur booléenne(data)]= false
[ 0 ], [type(data)]= number [valeur booléenne(data)]= false
[ 0 ], [type(data)]= number [valeur booléenne(data)]= false
[ 4.6 ], [type(data)]= number [valeur booléenne(data)]= true
[ {} ], [type(data)]= object [valeur booléenne(data)]= true
[ undefined ], [type(data)]= undefined [valeur booléenne(data)]= false
---------------[Conversion explicite vers un nombre]------------------------------
[data= 12.45 ], [type(data)]= string [nombre]= 12.45 [type(nombre)]= number
[data= 67.8 ], [type(data)]= number [nombre]= 67.8 [type(nombre)]= number
[data= true ], [type(data)]= boolean [nombre]= 1 [type(nombre)]= number
[data= null ], [type(data)]= object [nombre]= 0 [type(nombre)]= number
---------------[Conversion explicite vers un string]------------------------------
[data= 5 ], [type(data)]= number [chaîne]= 5 [type(chaîne)]= string
[data= 6.7 ], [type(data)]= number [chaîne]= 6.7 [type(chaîne)]= string
[data= false ], [type(data)]= boolean [chaîne]= false [type(chaîne)]= string
[data= null ], [type(data)]= object [chaîne]= null [type(chaîne)]= string
---------------[Autres cas]------------------------------
data1= 1000.781.034 type= string
data2= 1.0341000.78 type= string
data3= 1001.814 type= number
data4= 1.18 type= number
data5= 0 type= number