Concetti di base di JavaScript
Indice
Il capitolo si rivolge a chi non conosce il linguaggio, e copre i concetti di base e problemi comuni che possono sorgere quando si lavora con esso. Inoltre, la sezione può essere utile a chi utilizza altri linguaggi di programmazione per capire le peculiarità di JavaScript.
Se siete interessati a saperne di più sul linguaggio, si può leggere il libro JavaScript: The Good Parts che Douglas Crockford ha scritto.
2.1: Dichiarazione semplice di una variabile
var foo = 'ciao mondo';
var foo = 'ciao mondo';
2 * 3 + 5; // ritorna 11; il prodotto si esegue prima 2 * (3 + 5); // ritorna 16; per le parentesi, la somma si esegue prima
var foo = function() { console.log('ciao'); };
2.5: Concatenazione
var foo = 'ciao'; var bar = 'mondo'; console.log(foo + ' ' + bar); // 'ciao mondo'
2 * 3; 2 / 3;
var i = 1; var j = ++i; // incremento anticipato: j è uguale a 2; i è uguale a 2 var k = i++; // incremento posticipato: k è uguale a 2; i è uguale a 3
2.8: Somma vs. concatenazione
var foo = 1; var bar = '2'; console.log(foo + bar); // errore: la console di debug mostra 12
var foo = 1; var bar = '2'; // il costruttore 'Number' obbliga alla // stringa di comportarsi come un numero console.log(foo + Number(bar)); // la console di debug mostra 3
2.10: Forzare una stringa per agire come un numero (somma unaria)
console.log(foo + +bar);
2.11: Operatori Logici AND e OR
var foo = 1; var bar = 0; var baz = 2; foo || bar; // ritorna 1, il quale è vero (true) bar || foo; // ritorna 1, il quale è vero (true) foo && bar; // ritorna 0, il quale è falso (false) foo && baz; // ritorna 2, il quale è vero (true) baz && foo; // ritorna 1, il quale è vero (true)
È possibile consultare la sezione “Elementi Vero e Falso” per ulteriori dettagli su quali valori vengono valutati come true
e quali vengono valutati come false
.
Talvolta si può notare che alcuni sviluppatori utilizzino questa logica per il controllo del flusso invece di utilizzare la dichiarazione if. Per Esempio:
// fare qualcosa con foo se foo è vero foo && doSomething(foo); // stabilire bar uguale a baz se baz è vero; // caso contrario, stabilire bar uguale al // valore di createBar() var bar = baz || createBar();
2.12: Operatori di confronto
var foo = 1; var bar = 0; var baz = '1'; var bim = 2; foo == bar; // ritorna false foo != bar; // ritorna true foo == baz; // ritorna true; fare attenzione! foo === baz; // ritorna false foo !== baz; // ritorna true foo === parseInt(baz); // ritorna true foo > bim; // ritorna false bim > baz; // ritorna true foo <= baz; // ritorna true
2.13: Controllo del flusso
var foo = true; var bar = false; if (bar) { // questo codice non verrà mai eseguito console.log('ciao!'); } if (bar) { // questo codice non si eseguirà } else { if (foo) { // questo codice si eseguirà } else { // si eseguirà se foo e bar sono falsi (false) } }
In una linea singola, quando si scrive un’istruzione if, le parentesi non sono strettamente necessari, ma è raccomandato in quanto rende il codice molto più leggibile.
È necessario essere consapevoli di non definire funzioni con lo stesso nome più volte all’interno di istruzioni if/else, giacché si potrebbe ottenere risultati inaspettati.
2.14: Valori che ritornano il vero true
'0'; 'qualunque stringa'; []; // un array vuoto {}; // un oggetto vuoto 1; // qualsiasi numero diverso da zero
0; ''; // una stringa vuota NaN; // la variabile JavaScript "not-a-number" (non è un numero) null; // un valore nullo undefined; // // fare attenzione -- (undefined) può essere ridefinito
switch (foo) { case 'bar': alert('il valore è bar'); break; case 'baz': alert('il valore è baz'); break; default: alert('impostazione predefinita, questo codice verrà eseguito'); break; }
Per Esempio:
var stuffToDo = { 'bar' : function() { alert('il valore è bar'); }, 'baz' : function() { alert('il valore è baz'); }, 'default' : function() { alert('impostazione predefinita, questo codice verrà eseguito'); } }; if (stuffToDo[foo]) { stuffToDo[foo](); } else { stuffToDo['default'](); }
2.18: Cicli
// mostra nella console 'tentativo 0', 'tentativo 1', ..., 'tentativo 4' for (var i=0; i<5; i++) { console.log('tentativo ' + i); }
Si noti che nell’esempio si utilizza la parola var prima della variabile i, questo significa che detta variabile è all’interno della sua portata, o ambito, (in inglese scope) del ciclo. Più avanti in questo capitolo si esaminerà in modo approfondito il concetto di portata.
for ([espressioneIniziale]; [condizione]; [incrementoDellaEspressione]) [corpoCiclo]
Lo stato condizione viene eseguita prima di ogni iterazione, e restituisce un valore che decide se il ciclo deve continuare oppure no. Se lo stato condizionale valuta un valore come falso il ciclo si interrompe.
Lo stato incrementoDellaEspressione viene eseguito alla fine di ogni ripetizione e offre l’opportunità di modificare lo stato di variabili importanti. Di solito, questo stato comporta l’incremento o il decremento di un contatore.
Il corpoCiclo è il codice da eseguire in ogni iterazione del ciclo. In genere ci sono più istruzioni che devono essere eseguiti e così li avvolgono in un blocco ({…}).
Un tipico ciclo utilizzando for:
2.19: Un tipico ciclo utilizzando for
for (var i = 0, limit = 100; i < limit; i++) { // Questo blocco di codice viene eseguito 100 volte console.log('Attualmente a ' + i); // Nota: L'ultimo record da visualizzare // nella console sarà "Attualmente a 99" }
for ([espressioneIniziale]; [condizione]; [incrementoDellaEspressione]) [corpoCiclo]
2.20: Un típico bucle utilizzando while
var i = 0; while (i < 100) { // Questo blocco di codice verrà eseguito 100 volte console.log('Attualmente a ' + i); i++; // incrementa la variabile i }
2.21: Ciclo utilizzando while con la combinazione della condizione e l'incremento
var i = -1; while (++i < 100) { // Questo blocco di codice verrà eseguito 100 volte console.log('Attualmente a ' + i); }
do [corpoCiclo] while ([condizione])
do { // Anche quando la condizione è falsa // il corpo del ciclo viene eseguito almeno una volta. alert('Ciao!'); } while (false);
2.23: Fermare un ciclo con break
for (var i = 0; i < 10; i++) { if (qualcosa) { break; } }
2.24: Saltare alla seguente iterazione di un ciclo
for (var i = 0; i < 10; i++) { if (qualcosa) { continue; } // La seguente dichiarazione sarà eseguita // se la condizione 'something' non si compie console.log('I have been reached'); }
abstract
boolean
break
byte
case
catch
char
class
const
continue
debugger
default
delete
do
double
else
enum
export
extends
final
finally
float
for
function
goto
if
implements
import
in
instanceof
int
interface
long
native
new
package
private
protected
public
return
short
static
super
switch
synchronized
this
throw
throws
transient
try
typeof
var
void
volatile
while
with
2.25: Un vettore semplice
var myArray = [ 'ciao', 'mondo' ];
var myArray = [ 'ciao', 'mondo' ];
var myArray = [ 'ciao', 'mondo' ]; console.log(myArray.length); // mostra '2' nella console
var myArray = [ 'ciao', 'mondo' ]; myArray[1] = 'modificato';
Come mostrato nell’esempio “Modificare il valore di un elemento di un array” è possibile modificare il valore di un elemento di un array, in genere non è consigliabile.
2.29: Aggiungere elementi ad un array
var myArray = [ 'ciao', 'mondo' ]; myArray.push('nuovo');
var myArray = [ 'c', 'i', 'a', 'o' ]; var myString = myArray.join(''); // 'ciao' var mySplit = myString.split(''); // [ 'c', 'i', 'a', 'o' ]
È interessante notare che in JavaScript, quasi tutto è un oggetto – array, funzioni, numeri, anche le stringhe – e tutti possiedono proprietà e metodi.
var myObject = { sayHello : function() { console.log('ciao'); }, myName : 'Rebecca' }; myObject.sayHello(); // si chiama il metodo sayHello, che // visualizza sulla console 'Ciao' console.log(myObject.myName); // si chiama la proprietà myName, che // mostra 'Rebecca' nella console
var myObject = { validIdentifier: 123, 'qualche stringa': 456, 99999: 789 };
Gli oggetti letterali possono essere molto utile per l’organizzazione del codice, per maggiori informazioni potete leggere l’articolo (in inglese) Using Objects to Organize Your Code di Rebecca Murphey.
Le funzioni possono essere creati in diversi modi:
2.32: Dichiarazione di una funzione
function foo() { /* fa qualcosa */ }
var foo = function() { /* fa qualcosa */ }
Utilizzo delle Funzioni
var greet = function(person, greeting) { var text = greeting + ', ' + person; console.log(text); }; greet('Rebecca', 'Ciao');
var greet = function(person, greeting) { var text = greeting + ', ' + person; return text; }; console.log(greet('Rebecca','ciao'));
var greet = function(person, greeting) { var text = greeting + ', ' + person; return function() { console.log(text); }; }; var greeting = greet('Rebecca', 'Ciao'); greeting();
2.37: Una funzione anonima autoeseguibile
(function(){ var foo = 'Ciao mondo'; })(); console.log(foo); // indefinito (undefined)
2.38: Passare una funzione anonima come argomento
var myFn = function(fn) { var result = fn(); console.log(result); }; // mostra nella console 'Ciao mondo' myFn(function() { return 'Ciao mondo'; });
var myFn = function(fn) { var result = fn(); console.log(result); }; var myOtherFn = function() { return 'Ciao mondo'; }; // mostra nella console 'Ciao mondo' myFn(myOtherFn);
Per ciò, è pratica comune usare l’operatore typeof quando si tratta di determinare il tipo di un valore specifico.
2.40: Determinare il tipo tra differenti variabili
var myFunction = function() { console.log('ciao'); }; var myObject = { foo : 'bar' }; var myArray = [ 'a', 'b', 'c' ]; var myString = 'ciao; var myNumber = 3; typeof myFunction; // ritorna 'function' typeof myObject; // ritorna 'object' typeof myArray; // ritorna 'object' -- fare attenzione typeof myString; // ritorna 'string'; typeof myNumber; // ritorna 'number' typeof null; // ritorna 'object' -- fare attenzione if (myArray.push && myArray.slice && myArray.join) { // probabilmente è un array // (questo stile è chiamato, in inglese, "duck typing") } if (Object.prototype.toString.call(myArray) === '[object Array]') { // definitivamente è un array; // questa è considerata la forma più robusta // per determinare se un valore è un array. }
- Se la funzione viene invocata utilizzando Function.call o Function.apply,
this
avrà il valore del primo argomento passato al metodo. Se l’argomento è nullo (null) o indefinito (undefined),this
farà riferimento all’oggetto globale (l’oggettowindow
); - Se la funzione a invocare viene creata utilizzando Function.bind,
this
sarà il primo argomento che viene passato alla funzione, al momento della sua creazione; - Se la funzione è invocata come metodo di un oggetto,
this
farà riferimento a detto oggetto; - Altrimenti, se la funzione viene invocata come una funzione indipendente, non legata ad alcun oggetto,
this
farà riferimento all’oggetto globale.
var myObject = { sayHello : function() { console.log('Ciao! il mio nome è ' + this.myName); }, myName : 'Rebecca' }; var secondObject = { myName : 'Colin' }; myObject.sayHello(); // registra 'Ciao, il mio nome è Rebecca' myObject.sayHello.call(secondObject); // registra 'Ciao, il mio nome è Colin'
var myName = 'the global object', sayHello = function () { console.log('Ciao, il mio nome è ' + this.myName); }, myObject = { myName : 'Rebecca' }; var myObjectHello = sayHello.bind(myObject); sayHello(); // registra 'Ciao, il mio nome è oggetto globale' myObjectHello(); // registra 'Ciao, il mio nome è Rebecca'
var myName = 'oggetto globale', sayHello = function() { console.log('Ciao, il mio nome è ' + this.myName); }, myObject = { myName : 'Rebecca' }, secondObject = { myName : 'Colin' }; myObject.sayHello = sayHello; secondObject.sayHello = sayHello; sayHello(); // registra 'Ciao, il mio nome è oggetto globale' myObject.sayHello(); // registra 'Ciao, il mio nome è Rebecca' secondObject.sayHello(); // registra 'Ciao, il mio nome è Colin'
var myNamespace = { myObject : { sayHello : function() { console.log('Ciao, il mio nome è ' + this.myName); }, myName : 'Rebecca' } }; var hello = myNamespace.myObject.sayHello; hello(); // registra 'Ciao, il mio nome è undefined'
var myNamespace = { myObject : { sayHello : function() { console.log('Ciao!, il mio nome è ' + this.myName); }, myName : 'Rebecca' } }; var obj = myNamespace.myObject; obj.sayHello(); // registra 'Ciao!, il mio nome è Rebecca'
Quando una variabile viene dichiarata all’interno di una funzione utilizzando la parola chiave var, è disponibile solo per il codice all’interno della funzione – tutto il codice al di fuori della funzione non può accedere alla variabile. D’altra parte, le funzioni definite all’interno della funzione potranno accedere alla variabile dichiarata.
Le variabili dichiarate all’interno della funzione senza la parola chiave var non rimangono nell’ambito di applicazione della stessa funzione – JavaScript cercherà il luogo dove la variabile è stata precedentemente dichiarata, e nel caso che non sia stata dichiarata, sarà definita nell’ambito globale, il quale può portare a risultati inattesi;
2.44: Le funzioni hanno accesso alle variabili definite all'interno dello stesso ambito
var foo = 'Ciao'; var sayHello = function() { console.log(foo); }; sayHello(); // mostra nella console 'Ciao' console.log(foo); // mostra anche nella console 'Ciao'
var sayHello = function() { var foo = 'Ciao'; console.log(foo); }; sayHello(); // mostra nella console 'Ciao' console.log(foo); // non mostra niente nella console
var foo = 'mondo'; var sayHello = function() { var foo = 'ciao'; console.log(foo); }; sayHello(); // mostra nella console 'ciao' console.log(foo); // mostra nella console 'mondo'
var myFunction = function() { var foo = 'Ciao'; var myFn = function() { console.log(foo); }; foo = 'mondo'; return myFn; }; var f = myFunction(); f(); // registra 'mondo' -- errore
// a self-executing anonymous function (function() { var baz = 1; var bim = function() { alert(baz); }; bar = function() { alert(baz); }; })(); console.log(baz); // La console non mostra nulla, // visto che baz è definita nell'ambito // della funzione anonima bar(); // bar è definita al di fuori della funzione // anonima dopo essere stata dichiarata senza la // parola chiave var; inoltre, come è stata // definita all'interno della stessa portata di // baz, è possibile interrogare il valore del baz, // anche se questa sia definita all'interno // della portata della funzione anonima bim(); // bim non è definito per essere accessibile // al di fuori della funzione anonima, // quindi viene visualizzato un errore
Nell’sempio 2.47 il modo in cui le funzioni hanno accesso per cambiare il valore delle variabili. Lo stesso comportamento si verifica nelle funzioni create all’interno dei cicli – la funzione “osserva” il cambiamento nella variabile, anche dopo che la funzione sia stata definita, risultando che ad ogni click appaia una finestra di avviso mostrando il valore 5.
2.49: Come impostare il valore di i?
/* questo non si comporta come desiderato */ /* ogni click visualizzerà una finestra di avviso con il valore 5 */ for (var i=0; i<5; i++) { $('<p>click me</p>').appendTo('body').click(function() { alert(i); }); }
/* soluzione: "clausurare" il valor di i all'interno di createFunction */ var createFunction = function(i) { return function() { alert(i); }; }; for (var i=0; i<5; i++) { $('<p>click me</p>').appendTo('body').click(createFunction(i)); }
2.51: Utilizzando una chiusura per accedere simultaneamente ad istanze di oggetti interni ed esterni
var outerObj = { myName : 'esterno', outerFunction : function () { // fornisce un riferimento allo stesso oggetto outerObj // da utilizzare all'interno di innerFunction var self = this; var innerObj = { myName : 'interno', innerFunction : function () { console.log(self.myName, this.myName); // registra 'esterno interno' } }; innerObj.innerFunction(); console.log(this.myName); // registra 'esterno' } }; outerObj.outerFunction();
Ancora nessun commento