Grazie a
Siamo davvero sicuri di conoscere
Javascript?
Sicuri sicuri?!?
<g>
Agenda
• L’obiettivo: organizzare la codebase
• Javascript: un po' di storia
• Partire dalla fine: Model-View-ViewModel
• Namespace e Module pattern
• Pattern di creazione oggetti ed ereditarietà
• Il perché dei pattern: alla base di Javascript
(scoping, hoisting, closures, oggetto di
contesto, …)
L'obiettivo
• Il Web 2.0 e HTML5 rendono centrale lo sviluppo
software client
• La codebase Javascript diventa sempre più estesa e
complessa
• Per un professionista diventa fondamentale
l'organizzazione della codebase Javascript ai fini
della manutenibilità generale
• È necessario conoscere Javascript e i suoi pattern
strutturali/idiomatici
Un po' di storia
• Nato fra il 1995 e il 1996 nei laboratori della
Netscape, ideato da Brendan Eich, prima con
il nome di Mocha, poi LiveScript, infine
Javascript (debuttando con Netscape 2.0)
• Nel 1996 fu subito sottoposto alla ECMA che
da allora ne standardizza la definizione
(ECMAScript), oggi siamo alla versione 5.1
L'ideatore di Javascript
"JS had to 'look like Java' only less so, be Java’s dumb kid brother or
boy-hostage sidekick. Plus, I had to be done in ten days or
something worse than JS would have happened."
"JS doveva 'sembrare Java', solo un po' meno, essere il suo fratellino
imbranato o il suo partner inesperto. In più dovevo essere pronto in
dieci giorni o sarebbe accaduto qualcosa di peggio di JS."
Brendan Eich, 2010
Il grande equivoco
• Nonostante le parole di Eich:
– Javascript non è il fratellino "scemo" di Java
– Javascript in effetti non c'entra (quasi) nulla con
Java (anzi somiglia più a LISP, Ruby, …)
– Javascript non è un mero linguaggio di scripting
– Javascript ha un suo preciso formalismo che deve
essere assecondato
Chi è Javascript
• È un linguaggio interpretato (non compilato)
• È un linguaggio a tipizzazione dinamica
• È un linguaggio a scope lessicale (scope a
livello di definizione non a runtime)
• È un linguaggio che supporta OO
• Soprattutto è il linguaggio con la più infelice
e fuorviante denominazione
Servizi
Un esempio: Model-View-ViewModel
View (Code)
new MyView()
…
View (UI)
<tag>
…
</tag>
ViewModel
new MyViewModel()
…
Binding
Model
new MyModel()
…
Model
new MyModel()
…
Servizi
(REST, …)
Model-View-ViewModel: Messenger
Messenger ViewModel
ViewModel
ViewModel
View (Code)
View (Code)
View (Code)
Send
Subscribe
M-V-VM: organizzare la codebase
• Che cosa serve:
– Namespace per strutturare il codice, evitare
duplicazione di "simboli"
– "Classi" per implementare model, view, view
model, messenger, utilities, service proxies, …
M-V-VM: organizzare la codebase
• Che cosa offre Javascript:
– Non ha namespace
– Non ha classi
– Ha "solo" oggetti
Javascript: tutto è un oggetto
• In Javascript tutto è un oggetto:
– L’oggetto globale d'ambiente: es. window
– L'oggetto del contesto di esecuzione: this
– Un semplice oggetto: {…}
– Un array: […]
– Un tipo di dato built in: number, string, …
– Una variabile: var foo
– Una funzione: function bar(){…}
"Instrumentare" Javascript
• È possibile ottenere da Javascript ciò di cui
si ha bisogno (namespace, classi, …)
utilizzando pattern strutturali/idiomatici di
programmazione che si basano sulle sue
peculiarità
• Instrumentare Javascript serve anche ad
evitare le "trappole" insite nel linguaggio
Namespace pattern
• In Javascript è fin troppo facile definire
variabili globali
• Strutturare la codebase per namespace
evita la collisione e l'eccessivo uso di
prefissi delle denominazioni (variabili e
funzioni)
Javascript: scoping delle variabili
• In Javascript lo scoping è lessicale
• Lo scoping locale di una variabile:
– È fissato a livello di definizione di funzione
(function) se dichiarato tramite var, altrimenti
è globale
– Non è a livello di blocco (ovvero individuato a
runtime secondo il ciclo di vita di una blocco
di codice)
Javascript: scoping delle variabili
var foo = "foo";
function bar() {
var foo = "bar";
//locale "bar"
alert(foo);
}
//globale "foo"
alert(foo);
function bar() {
foo = "bar";
//globale "bar"
alert(foo);
}
//globale "bar"
alert(foo);
Javascript: closure
• In Javascript le funzioni sono oggetti
• Le funzioni hanno scope lessicale che
determina la creazione di un oggetto di
scope chain associato alla funzione (e che
sopravvive all'esecuzione della funzione
stessa)
• Tecnicamente parlando queste due condizioni
identificano una closure
Namespace pattern
CDays12.namespace = function (ns_string) {
var parts = ns_string.split('.'),
parent = CDays12;
if (parts[0] === "CDays12") {
parts = parts.slice(1);
}
for (var i = 0; i < parts.length; i += 1) {
if (typeof parent[parts[i]] === "undefined") {
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
};
Namespace pattern
CDays12.namespace("CDays12.Foo.Bar");
CDays12 = {
Foo: {
Bar: {
}
}
}
Module pattern
• Il Module pattern estende il concetto di
Namespace aggiungendo:
– Uso idiomatico delle immediate functions
per creare un ambiente sandbox "protetto"
– Membri privati e pubblici (privilegiati)
Module pattern
Immediate functions: notazione idiomatica
che permette di "auto-eseguire" una
function expression
(function () {
alert("Hello world!");
}());
Funzioni in Javascript
function Foo(bar) {
//function definition (ATTENZIONE: non è un oggetto!)
}
var foo = function Foo(bar) {
//named function expression
}
var foo = function(bar) {
//function expression (anonymous function)
}
myObj.foo = function(bar) {
//method invocation
}
Module pattern
• Usare una immediate function permette di
assegnare ad un oggetto namespace una
sorta di sandbox protetta in cui definire
denominazioni interne al namespace
stesso evitandone la duplicazione
Module pattern
CDays12.namespace("CDays12.Foo.Bar");
CDays12.Foo.Bar = (function() {
//codice
return {
myVar: "Hello World!"
}
}());
Javascript e le classi
• In Javascript formalmente non esistono le
classi intese come definizione statica di un
tipo da declinare in oggetti tramite
istanziazione
• È possibile simulare la definizione di una
classe mediante un uso accorto delle
custom constructor function
Custom constructor functions
• Una funzione se chiamata tramite la parola
chiave new si comporta come se fosse un
costruttore in cui l'oggetto di contesto this
si riferisce all'oggetto effettivamente in
costruzione
Custom constructor functions
var Foo = function() {
this.bar = function() {
return "Hello World!";
}
};
var foo = new Foo();
foo.bar() //"Hello World!"
Module pattern e costruttori
CDays12.namespace("CDays12.Foo");
CDays12.Foo = (function() {
var ctor = function() {
this.bar = function() { return "Hello World!" };
};
ctor.prototype = {
constructor: CDays12.Foo,
name: "CDays12.Foo",
version: "1.0"
};
return ctor;
}());
var foo = new CDays12.Foo();
Javascript ed ereditarietà
• Anche per quanto riguarda l'ereditarietà
non esiste il concetto di ereditarietà di tipo
• Anche l'ereditarietà può essere simulata in
Javascript, sempre tramite le custom
constructor function e l'uso del metodo
standard apply
Rent-a-Constructor pattern
var BaseFoo = function() {
this.bar = function() {
return "Hello World!";
}
};
var Foo = function() {
BaseFoo.apply(this, arguments);
};
var foo = new Foo();
foo.bar() //"Hello World!"
Altre caratteristiche di Javascript
• Ci sono anche altre caratteristiche proprie
del linguaggio che sono fondamentali, in
particolare:
– Hosting dello scope
– Scoping dell'oggetto di contesto (this)
Hoisting dello scope
• Non solo lo scope locale di una variabile è a
livello di function, ma la sua dichiarazione è
valida all’interno di tutta la function
• In pratica la dichiarazione è come se fosse
fatta all’inizio della funzione (viene
sollevata/hoisted)
• Le function definition sono hoisted non solo
per quanto riguarda la dichiarazione, ma
anche per quanto riguarda la definizione
Hoisting dello scope
var foo = "foo";
function bar() {
//locale undefined
alert(foo)
var foo = "bar";
//locale "bar"
alert(foo);
}
//globale "foo"
alert(foo);
Difendersi dall'hoisting
• Per difendersi dall'hoisting è sempre bene
dichiarare ed eventualmente inizializzare
tutte le variabili subito all'inizio della
funzione
Oggetto di contesto
• Ogni chiamata a funzione, durante
l'esecuzione della stessa, individua un
oggetto di contesto accessibile tramite la
parola chiave this
• L'oggetto di contesto non è soggetto a
scope lessicale
Oggetto di contesto
• A seconda del contesto di esecuzione this si riferisce ad
oggetti diversi
– Custom constructor functions: oggetto in
costruzione
– Method invocation: oggetto su cui si sta invocando il
metodo
– Function definition: oggetto globale
– Callback function: oggetto di contesto della funzione
che invoca la callback anche se la callback è un
metodo di un altro oggetto
Oggetto di contesto
• È possibile imporre l'oggetto di contesto ad un funzione
invocandola tramite i metodi standard apply e call
var foo = function(bar) {
return this.prop + bar;
}
foo.apply(myObj, [ bar ]); //this === myObj
foo.call(myObj, bar); //this === myObj
Minificazione delle risorse Javascript
• Una controindicazione all'organizzazione
della codebase in questi termini è la
proliferazione delle risorse Javascript che
può impattare negativamente sulle
performance di una pagina web
• Per ovviare a questo problema è possibile
usare librerie di minificazione al volo come
Combres, Yahoo! YUICompressor o Google
Closure Compiler
Bibliografia
• Javascript Patterns
– Stoyan Stefanov
– O'Reilly editore
– Anno 2010
Q&A
• Materiale su
http://www.communitydays.it/

Javascript avanzato: sfruttare al massimo il web

  • 2.
  • 3.
    Siamo davvero sicuridi conoscere Javascript?
  • 4.
  • 5.
    Agenda • L’obiettivo: organizzarela codebase • Javascript: un po' di storia • Partire dalla fine: Model-View-ViewModel • Namespace e Module pattern • Pattern di creazione oggetti ed ereditarietà • Il perché dei pattern: alla base di Javascript (scoping, hoisting, closures, oggetto di contesto, …)
  • 6.
    L'obiettivo • Il Web2.0 e HTML5 rendono centrale lo sviluppo software client • La codebase Javascript diventa sempre più estesa e complessa • Per un professionista diventa fondamentale l'organizzazione della codebase Javascript ai fini della manutenibilità generale • È necessario conoscere Javascript e i suoi pattern strutturali/idiomatici
  • 7.
    Un po' distoria • Nato fra il 1995 e il 1996 nei laboratori della Netscape, ideato da Brendan Eich, prima con il nome di Mocha, poi LiveScript, infine Javascript (debuttando con Netscape 2.0) • Nel 1996 fu subito sottoposto alla ECMA che da allora ne standardizza la definizione (ECMAScript), oggi siamo alla versione 5.1
  • 8.
    L'ideatore di Javascript "JShad to 'look like Java' only less so, be Java’s dumb kid brother or boy-hostage sidekick. Plus, I had to be done in ten days or something worse than JS would have happened." "JS doveva 'sembrare Java', solo un po' meno, essere il suo fratellino imbranato o il suo partner inesperto. In più dovevo essere pronto in dieci giorni o sarebbe accaduto qualcosa di peggio di JS." Brendan Eich, 2010
  • 9.
    Il grande equivoco •Nonostante le parole di Eich: – Javascript non è il fratellino "scemo" di Java – Javascript in effetti non c'entra (quasi) nulla con Java (anzi somiglia più a LISP, Ruby, …) – Javascript non è un mero linguaggio di scripting – Javascript ha un suo preciso formalismo che deve essere assecondato
  • 10.
    Chi è Javascript •È un linguaggio interpretato (non compilato) • È un linguaggio a tipizzazione dinamica • È un linguaggio a scope lessicale (scope a livello di definizione non a runtime) • È un linguaggio che supporta OO • Soprattutto è il linguaggio con la più infelice e fuorviante denominazione
  • 11.
    Servizi Un esempio: Model-View-ViewModel View(Code) new MyView() … View (UI) <tag> … </tag> ViewModel new MyViewModel() … Binding Model new MyModel() … Model new MyModel() … Servizi (REST, …)
  • 12.
  • 13.
    M-V-VM: organizzare lacodebase • Che cosa serve: – Namespace per strutturare il codice, evitare duplicazione di "simboli" – "Classi" per implementare model, view, view model, messenger, utilities, service proxies, …
  • 14.
    M-V-VM: organizzare lacodebase • Che cosa offre Javascript: – Non ha namespace – Non ha classi – Ha "solo" oggetti
  • 15.
    Javascript: tutto èun oggetto • In Javascript tutto è un oggetto: – L’oggetto globale d'ambiente: es. window – L'oggetto del contesto di esecuzione: this – Un semplice oggetto: {…} – Un array: […] – Un tipo di dato built in: number, string, … – Una variabile: var foo – Una funzione: function bar(){…}
  • 16.
    "Instrumentare" Javascript • Èpossibile ottenere da Javascript ciò di cui si ha bisogno (namespace, classi, …) utilizzando pattern strutturali/idiomatici di programmazione che si basano sulle sue peculiarità • Instrumentare Javascript serve anche ad evitare le "trappole" insite nel linguaggio
  • 17.
    Namespace pattern • InJavascript è fin troppo facile definire variabili globali • Strutturare la codebase per namespace evita la collisione e l'eccessivo uso di prefissi delle denominazioni (variabili e funzioni)
  • 18.
    Javascript: scoping dellevariabili • In Javascript lo scoping è lessicale • Lo scoping locale di una variabile: – È fissato a livello di definizione di funzione (function) se dichiarato tramite var, altrimenti è globale – Non è a livello di blocco (ovvero individuato a runtime secondo il ciclo di vita di una blocco di codice)
  • 19.
    Javascript: scoping dellevariabili var foo = "foo"; function bar() { var foo = "bar"; //locale "bar" alert(foo); } //globale "foo" alert(foo); function bar() { foo = "bar"; //globale "bar" alert(foo); } //globale "bar" alert(foo);
  • 20.
    Javascript: closure • InJavascript le funzioni sono oggetti • Le funzioni hanno scope lessicale che determina la creazione di un oggetto di scope chain associato alla funzione (e che sopravvive all'esecuzione della funzione stessa) • Tecnicamente parlando queste due condizioni identificano una closure
  • 21.
    Namespace pattern CDays12.namespace =function (ns_string) { var parts = ns_string.split('.'), parent = CDays12; if (parts[0] === "CDays12") { parts = parts.slice(1); } for (var i = 0; i < parts.length; i += 1) { if (typeof parent[parts[i]] === "undefined") { parent[parts[i]] = {}; } parent = parent[parts[i]]; } return parent; };
  • 22.
  • 23.
    Module pattern • IlModule pattern estende il concetto di Namespace aggiungendo: – Uso idiomatico delle immediate functions per creare un ambiente sandbox "protetto" – Membri privati e pubblici (privilegiati)
  • 24.
    Module pattern Immediate functions:notazione idiomatica che permette di "auto-eseguire" una function expression (function () { alert("Hello world!"); }());
  • 25.
    Funzioni in Javascript functionFoo(bar) { //function definition (ATTENZIONE: non è un oggetto!) } var foo = function Foo(bar) { //named function expression } var foo = function(bar) { //function expression (anonymous function) } myObj.foo = function(bar) { //method invocation }
  • 26.
    Module pattern • Usareuna immediate function permette di assegnare ad un oggetto namespace una sorta di sandbox protetta in cui definire denominazioni interne al namespace stesso evitandone la duplicazione
  • 27.
    Module pattern CDays12.namespace("CDays12.Foo.Bar"); CDays12.Foo.Bar =(function() { //codice return { myVar: "Hello World!" } }());
  • 28.
    Javascript e leclassi • In Javascript formalmente non esistono le classi intese come definizione statica di un tipo da declinare in oggetti tramite istanziazione • È possibile simulare la definizione di una classe mediante un uso accorto delle custom constructor function
  • 29.
    Custom constructor functions •Una funzione se chiamata tramite la parola chiave new si comporta come se fosse un costruttore in cui l'oggetto di contesto this si riferisce all'oggetto effettivamente in costruzione
  • 30.
    Custom constructor functions varFoo = function() { this.bar = function() { return "Hello World!"; } }; var foo = new Foo(); foo.bar() //"Hello World!"
  • 31.
    Module pattern ecostruttori CDays12.namespace("CDays12.Foo"); CDays12.Foo = (function() { var ctor = function() { this.bar = function() { return "Hello World!" }; }; ctor.prototype = { constructor: CDays12.Foo, name: "CDays12.Foo", version: "1.0" }; return ctor; }()); var foo = new CDays12.Foo();
  • 32.
    Javascript ed ereditarietà •Anche per quanto riguarda l'ereditarietà non esiste il concetto di ereditarietà di tipo • Anche l'ereditarietà può essere simulata in Javascript, sempre tramite le custom constructor function e l'uso del metodo standard apply
  • 33.
    Rent-a-Constructor pattern var BaseFoo= function() { this.bar = function() { return "Hello World!"; } }; var Foo = function() { BaseFoo.apply(this, arguments); }; var foo = new Foo(); foo.bar() //"Hello World!"
  • 34.
    Altre caratteristiche diJavascript • Ci sono anche altre caratteristiche proprie del linguaggio che sono fondamentali, in particolare: – Hosting dello scope – Scoping dell'oggetto di contesto (this)
  • 35.
    Hoisting dello scope •Non solo lo scope locale di una variabile è a livello di function, ma la sua dichiarazione è valida all’interno di tutta la function • In pratica la dichiarazione è come se fosse fatta all’inizio della funzione (viene sollevata/hoisted) • Le function definition sono hoisted non solo per quanto riguarda la dichiarazione, ma anche per quanto riguarda la definizione
  • 36.
    Hoisting dello scope varfoo = "foo"; function bar() { //locale undefined alert(foo) var foo = "bar"; //locale "bar" alert(foo); } //globale "foo" alert(foo);
  • 37.
    Difendersi dall'hoisting • Perdifendersi dall'hoisting è sempre bene dichiarare ed eventualmente inizializzare tutte le variabili subito all'inizio della funzione
  • 38.
    Oggetto di contesto •Ogni chiamata a funzione, durante l'esecuzione della stessa, individua un oggetto di contesto accessibile tramite la parola chiave this • L'oggetto di contesto non è soggetto a scope lessicale
  • 39.
    Oggetto di contesto •A seconda del contesto di esecuzione this si riferisce ad oggetti diversi – Custom constructor functions: oggetto in costruzione – Method invocation: oggetto su cui si sta invocando il metodo – Function definition: oggetto globale – Callback function: oggetto di contesto della funzione che invoca la callback anche se la callback è un metodo di un altro oggetto
  • 40.
    Oggetto di contesto •È possibile imporre l'oggetto di contesto ad un funzione invocandola tramite i metodi standard apply e call var foo = function(bar) { return this.prop + bar; } foo.apply(myObj, [ bar ]); //this === myObj foo.call(myObj, bar); //this === myObj
  • 41.
    Minificazione delle risorseJavascript • Una controindicazione all'organizzazione della codebase in questi termini è la proliferazione delle risorse Javascript che può impattare negativamente sulle performance di una pagina web • Per ovviare a questo problema è possibile usare librerie di minificazione al volo come Combres, Yahoo! YUICompressor o Google Closure Compiler
  • 42.
    Bibliografia • Javascript Patterns –Stoyan Stefanov – O'Reilly editore – Anno 2010
  • 43.

Editor's Notes

  • #2 Inserite l’eventuale vostro logo in basso a destra
  • #3 Slide da mostrare prima di iniziare la sessione – non rimuovere!
  • #44 Ultima slide, obbligatoria