Ormai più di una settimana ho tenuto il lab su Typescript su cui da tempo stavo lavorando. Vorrei ringraziare ancora una volta tutti quelli che hanno partecipato, per la solerzia con cui hanno seguito gli esempi e hanno provato ad implementare il codice che ho preparato. Ogni giorno che passa sono sempre più convinto che Typescript sia uno strumento insostituibile e ho trovato molte conferme in questo lab vedendo le persone progredire in fretta, mano a mano che prendevano confidenza con il linguaggio e si rendevano conto delle enormi potenzialità e tutela nei confronti del pure e semplice Javascript.

Ho pubblicato tutto il materiale nel repository di XeDotNet perciò potete scaricare tutto il necessario per provare voi stessi l'esempio. In particolare seguire il documento PDF - che ho cercato di rendere il più accurato ed autonomo possibile - nel quale troverete lo step-by-step e scaricate il progetto di base da cui partire. Se poi siete pigri troverete anche l'implementazione di tutti i vari passaggi.

Ecco il link al download: http://1drv.ms/1flJCDT

Al solito se avete problemi non esitate a contattarmi con la form del weblog.


Di fronte alla vostra prima applicazione con Typescript, vi sarete certamente chiesti quale sia il modo migliore per dare ad essa il primo avvio. Può sembrare una domanda banale ma, essa cela delle considerazioni che dovrebbero essere tenute nella dovuta attenzione. Prima di tutto, è certamente vero che del codice Javascript è anche del codice Typescript perfettamente valido ma, se ci lasciamo prendere la mano e iniziamo a scrivere così come eravamo abituati in precedenza rischiamo di perdere i benefici che Typescript può regalarci.

Primo fra tutti, sicuramente il fatto che Typescript accentua fortemente le caratteristiche object oriented e di conseguenza ci dovremmo attendere di rappresentare l’applicazione – intendendo con essa una singola pagina al cui interno gira il codice che le da vita – con una sola classe, che detenga i riferimenti ai vari elementi e naturalmente lo stato. Un po’ come avviene in una applicazione asp.net, in cui una sigola pagina è rappresentata dal suo “codebehind”.

Per avviare una applicazione del genere dovremmo di conseguenza creare al più presto l’istanza della classe e dare ad essa il controllo, lasciando che gestisca il ciclo di vita della pagina fino alla sua naturale conclusione. Per questo tipo di avvio sono abituato ad utilizzare un pattern ormai abbstanza consolidato. Creaimo una classe base per la pagina, in un namespace comune che i usialmente chiamo “sys”:

   1: module sys
   2: {
   3:     export class Page
   4:     {
   5:         public static run(page: Page): void
   6:         {
   7:             $(() => page.onLoad());
   8:         }
   9:  
  10:         public onLoad(): void { }
  11:     }
  12: }

Come di può vedere , la classe consta di un metodo statico “run” e di un metodo virtual “onLoad”. Attenzione che in Typescript il concetto di virtuale non esiste ma in realtà qualunque metodo pubblico è anche virtual. Diamo per assodato che sia presente jQuery e all’interno del metodo run usiamo l’evento “readystatechanged” con la classica sintatti $(…) dove all’interno delle parentesi va indicata una funzione eseguita all’occorrenza di questo evento. A questo punto possiamo ereditare il codebehind concreto della pagina da sys.Page:

   1: class DefaultPage extends sys.Page
   2: {
   3:     constructor()
   4:     {
   5:         super();
   6:  
   7:         // inizializazione della pagina
   8:     }
   9:  
  10:     public onLoad(): void
  11:     {
  12:         // iniziamo qui il ciclo di vita
  13:     }
  14: }

In particolare nella classe viene riferinito il metodo onLoad che sarà chiamato automaticamente quando viene eseguito il “readystatechanged”. Potremmo così nel costruttore inizializzare i campi della classe, i valori di default, e così via mentre nell’onLoad potremmo cercare gli elementi della pagina, ed avviare eventuali operazioni di download da un servizio rest. L’avvio della pagina avviene per mezzo di una singola riga, posta usualmente in coda alla pagina o in un file ts:

   1: sys.Page.run(new DefaultPage());

La singola riga crea l’istanza della classe DefaultPage e poi vi da avvio con il metodo statico “run”. Niente di più semplice e pulito. Per estensione, se identificate all’interno della pagina diverse aree, a ciascuna delle quali risponda una classe Typescript che ne incapsuli il funzionamento, potete tranquillamente usare la stessa tecnica e ciascuna classe sarà avviata separatamente con il medesimo ciclo.

Di questo e di altro parleremo in occasione del Community LAB che si terrà il prossimo 28/2/2014 a Mestre. Se vi unite a me con il vostro PC sarà mia cura guidarvi nello sviluppo con questo semplice ma “liberatorio” linguaggio.

Iscrizioni e dettagli: http://www.xedotnet.org/Home/Meeting/20140228



typescript-bannerGiusto quest’oggi si sono aperte le iscrizioni al LAB su Typescript che si terrà il prossimo 28 Febbraio a Mestre – Venezia. Nell’occasione avremo modo di affrontare questo interessante linguaggio che ha il non trascurabile scopo di semlificare lo sviluppo client side all’interno dei browser. Typescript infatti gode infatti di un compilatore (che curiosamente è scritto esso stesso in Typescript) che è in grado di convertire il codice in Javascript puro, capace di essere eseguito in qualunque browser, senza necessità di un plugin addizionale. Si tratta in effetti della nemesi, regalandoci un linguaggio di alto livello – anche se mantenendo degli interessanti risvolti semantici che lo rendono flessibile come Javascript – dotato di un set di tipi verificato a compile-time.

Chi desiderasse approfondire lo può fare nei seguenti post:

Chi di voi invece preferisse provare direttamente un esempio, può raggiungermi il 28/2 a Mestre, iscrivendosi al seguente link.

http://www.xedotnet.org/Home/Meeting/20140228

Durante il lab darò una infarinatura iniziale del linguaggio e in seguito potrete seguire un esercizio step-by-step, e porre le domande del caso per risolvere i vostri problemi reali.

A presto


Una questione di fondamentale importanza, quando si lavora con Javascript, è l'utilizzo delle più comuni librerie di terze parti. Se ne possono nominare innumerevoli - tra le più conosciute troviamo as esempio JQuery - e sicuramente ne rimarrebbero fuori altrettante. Gran parte del successo di Javascript in effetti dipende dalla disponibilità di questi insostituibili strumenti, più che dal linguaggio stesso. Nel passare a Typescript, non è possibile immaginare il successo di un linguaggio che non tenga conto di questa peculiarità, ed infatti, cardine nella progettazione del linguaggio è stato proprio il fatto che tali librerie potessero funzionare senza alcun tipo di modifica.

I definition file

Se si prova ad analizzare con calma quello che ci si presenta davanti agli occhi quando scriviamo in Typescript, diventa immediatamente chiaro che, aldilà di un linguaggio efficace, c'è anche dell'altro. Proviamo ad esempio, in un banale esercizio a scrivere quanto segue:

   1: var element: HTMLAnchorElement = 
   2:     <HTMLAnchorElement>document.getElementById('myLink');
   3: element.href = 'http://www.xamlplayground.org';

La specifica di HTMLAnchorElement, qui utilizzata sia come dichiarazione di una variabile che come cast, in effetti rivela che vi è un substrato di tipi definiti che ci supportano nella stesura del codice, consentendo al compilatore di verificare che alle chiamate di proprietà e metodi rispondano costrutti che esistono realmente. Ora, se siamo in Visual Studio 2012, possiamo semplicemente andare con il cursore al tipo HtmlAnchorElement e premere F12 (Go To Definition) per ottenere quanto segue:

   1: interface HTMLAnchorElement extends HTMLElement, MSHTMLAnchorElementExtensions, MSDataBindingExtensions {
   2:     rel: string;
   3:     protocol: string;
   4:     search: string;
   5:     coords: string;
   6:     hostname: string;
   7:     pathname: string;
   8:     target: string;
   9:     href: string;
  10:     name: string;
  11:     charset: string;
  12:     hreflang: string;
  13:     port: string;
  14:     host: string;
  15:     hash: string;
  16:     rev: string;
  17:     type: string;
  18:     shape: string;
  19:     toString(): string;
  20: }
  21: declare var HTMLAnchorElement: {
  22:     prototype: HTMLAnchorElement;
  23:     new(): HTMLAnchorElement;
  24: }

Il codice qui evidenziato, corrispondente alla dichiarazione del tipo suddetto, è estrapolato da un file denominato "lib.d.ts". Questo file è automaticamente incluso al momento della compilazione ed è anche riconosciuto dall'intellisense di Visual Studio. Come si vede si tratta di una semplice dichiarazione ma la sua utilità, assieme a le innumerevoli altre presenti nel file, è di grande utilità per supportare lo sviluppo all'interno di una pagina HTML, esponendo oggetti, metodi, proprietà ed eventi.

I file di definizione in effetti possono essere facilmente redatti e inclusi nella compilazione del proprio codice, per supportare qualunque libreria di terze parti oppure propria. Infatti è importante ricordare che qualunque spezzone di codice Javascript valido è anche un Typescript valido, pertanto con il supporto di un file di definizione saremo nettamente agevolati nell'utilizzo di tali librerie.

Una libreria a caso... JQuery

Chiunque abbia sviluppato recentemente in Javascript non può esimersi dal riconoscere le enormi potenzialità di JQuery, che consente facilmente di interagire con il DOM della pagina e ottenere con semplicità dei risultati anche molto efficaci e accattivanti. Ed è scontato che la prima tentazione sarà quella di usare questa libreria in congiunzione con Typescript. Vediamo quindi di soddisfare immediatamente questa legittima esigenza e di spiegare nel contempo come comportarsi in questo caso.

La prima attività da compiere è quella di includere nella pagina JQuery stesso, prima del punto in cui il codice Javascript output del nostro Typescript è incluso. Questa operazione è fatta come comune utilizzando il tag <script> impostandone l'attributo "src" e serve a consentire al browser di caricare la libreria. In termini di sviluppo essa ha esclusivamente l'obbiettivo di consentirci il normale funzionamento del software ma, dal punto di vista delle definizioni non ha alcun effetto pratico. Per consentire al compilatore Typescript di conoscere le definizioni occorre innanzitutto procurarsi il file di definizione "jquery.d.ts". Esso è reperibile all'interno del repository di Typescript, tra gli esempi.

http://typescript.codeplex.com/sourcecontrol/latest#typings/jquery.d.ts

Il file in questione è relativo la versione 1.7 della libreria quindi occorre caricare nella pagina la corrispondente versione per essere certi di non avere sorprese. Una volta che il file è incluso nella soluzione esso deve essere referenziato dal nostro file Typescript con una sintassi basata su un commento:

/// <reference path="../Libs/typings/jquery/jquery.d.ts" />

Grazie a queta referenza il compilatore inizierà ad accorgersi della presenza di tipi di JQuery e di conseguenza a fornire l'intellisense come atteso:

imageAttenzione che la presenza di un file di definizione non ha solo lo scopo di supportare lo sviluppo alimentando l'intellisense. La vera utilità sta nel fatto che solo se il compilatore conosce i tipi sarà in grado di validare il nostro codice. Scrivere del codice che usa JQuery senza un file si definizione è pari a tentare di scrivere una classe C# senza gli opportuni "using".

E' del tutto evidente che la medesima tecnica può essere utilizzata anche per creare delle proprie librerie da condividere tra differenti progetti. Ma in tale caso potremmo anche esimerci dal utilizzare un file di definizioni, per collegare direttamente la libreria al sorgente:

/// <reference path="../Libs/Utils.ts" />

E' chiaro che all'interno di questo file importato dovremo organizzare i tipi secondo dei namespace opportunamente organizzati per facilitarne l'utilizzo.

   1: /// <reference path="typings/jquery/jquery.d.ts" />
   2:  
   3: module Utils
   4: {
   5:     export class Page
   6:     {
   7:         run(): void
   8:         {
   9:             $(() => this.onLoad());
  10:         }
  11:  
  12:         onLoad(): void { }
  13:     }
  14: }

Nello snippet si vede l'utilizzo di "module" per creare un namespace. All'interno di esso ciascuna classe che è marcata con "export" (ma attenzione che vale anche per proprietà, metodi, tipi statici e anche semplici variabili) diverrà visibile all'esterno. Questo consente una ottima organizzazione, mediante un corretto incapsulamento di tipi privati che supportano tipi pubblici. Nello stesso esempio si può vedere anche l'uso di una referenza a jquery.d.ts.

Spesso e volentieri ci si trova nell'esigenza di includere sempre i medesimi file, e quindi a replicare potenzialmente all'infinito le referenze. In tale caso sarà consigliabile creare un file references.ts che contenga le referenze utilizzate da tutti i componenti. A questo punto sarà sufficiente collegare sempre tale file a tutti i sorgenti e avremmo il beneficio di aver accentrato la definizione in un unico punto.

E le altre librerie?

Una volta compreso il meccanismo che sta alla base dei definition file, l'ultima cosa che rimane da fare è procurarsi le definizioni per le librerie di cui si necessita. Dato che pensare di scriversi in proprio una definizione è piuttosto azzardato e richiede un tempo e una attenzione di cui raramente si dispone, bisogna indirizzarsi alla rete. In particolare, su github esiste una collezione di definizioni molto estesa e aggiornata che potete trovare a questo indirizzo: https://github.com/borisyankov/DefinitelyTyped. Ma, da utenti di Visual Studio la cosa migliore è di accedere a nuget e cercare "Definitelytyped" associato al nome della libreria di cui si cercano le definizioni. Grazie a nuget sarà possibile accedere direttamente alle definizioni ed agganciarle al progetto.


Nel precedente articolo abbiamo visto rapidamante l'espressività che ci è consentita da Typescript nella dichiarazione di nostri tipi ed interfacce. Abbiamo anche evidenziato che il compilatore applica lo structured typing consentendoci di lavorare minimizzando le dichiarazioni, proprio perchè esso è in grado di identificare ricorrenze nella struttura dei tipi e verificare che siano soddisfatte. E' chiaro tuttavia che conoscere bene la semantica del linguaggio ci permette di sfruttarene al meglio l'espressività e adottare una migliore tecnica object oriented. L'obbiettivo di questo articolo è di approfondire l'utilizzo dei tipi, a partire dai semplici parametri fino alla definizione di classi e interfacce e nella loro ereditarietà.

I tipi e il loro utilizzo

Il caso più semplice e ricorrente nelle dichiarazioni è rappresentato da variabili e parametri di un metodo e da qui partiremo analizzando le peculiarità del linguaggi. Typescript ammette pochi e semplici tipi di base:

      1. number: numero reale. esso è trattato sempre come se si trattasse di un "double"

      2. string: stringa alfanumerica

      3. bool: valore booleano (true o false)

      4. any: è l'equivalente di una dichiarazione di tipo "variant" in quanto annulla il controllo del compilatore sui membri. Su un membro "any" può essere invocato qualunque metodo ma è onere del programmatore assicurarsi che esso esista.

      5. function: così come avviene per javascript, il compilatore ammette anche la dichiarazione di metodi che ammettano una funzione, consentendo ad esempio l'uso di callback.

    Tralasciano di tipi ovvi quali number, string e bool che dovrebbero essere di uso comune a chiunque e che obbiettivamente non presentano sorprese, vale la pena approfondire l'utilizzo di any e delle dichiarazioni di funzione:

       1: var theWindow : any = <any>window;
       2: theWindow.execute();

    La precedente dichiarazione rende la variabile myObject generica a tal punto che è possibile chiamare su di essa un metodo di cui typescript non conosce l'esistenza. Il caso illustrato è abbastanza comune quando in una pagina convive il codice javascript di una libreria di terze parti e il nostro typescript. Se una ipotetica libreria avesse dichiarato una funzione nel documento, Typescript non potrebbe conoscerla e di conseguenza il compilatore si interromperà con un errore. Ecco quindi che si effettua il cast di "window" ad "any" (il cast si indica con le parentesi angolari <any>) e a questo punto è possibile chiamare la funzione senza che il compilatore si impunti.

    Un altro caso particolare sono le variabili che ammettono come valore una funzione:

       1: var callback : (number) => string;
       2:  
       3: callback = function(n) 
       4: { 
       5:     return "The answer is " + n; 
       6: };
       7:  
       8: var result = callback(42);

    La variabile callback in questione viene dichiarata con una sintassi che mima quella delle lambda expression. La sintassi "(int) => string" identifica una funzione che ha un parametro intero e un valore di ritorno di tipo stringa.

    Inutile dire che è ammissibile avere funzioni senza parametri

    var callback : () => string

    con un valore di ritorno void

    var callback : (mynum: number) => void

    oppure con parametri multipli

    var callback : (mynum: number, mystring: string, mybool: bool) => string

    Interessante comunque notare che il compilatore non richiede che la funzione passata abbia esplicitato il tipo dei parametri ma, per mezzo dell'inferenza, applica automaticamente i tipi attesi. E' comunque sempre ammesso esplicitarli. Per passare una funzione alla variabile callback è possibile operare come nell'esempio, oppure utilizzare la sintassi lambda-expression come segue:

       1: var callback : (number) => string;
       2:  
       3: callback = (n) => { return "The answer is " + n };
       4:  
       5: var result = callback(42);

    Fin'ora per semplicità abbiamo visto le dichiarazioni applicate alle variabile, ma i medesimi tipi possono essere utilizzati anche per dichiare i parametri di un metodo piuttosto che le proprietà di una interfaccia o di una classe. Vediamo alcuni esempi:

       1: // metodo
       2:  
       3: function getRemoteData(callback: (result) => void) : void
       4: {
       5:     // download here
       6: }
       7:  
       8: // interfaccia
       9:  
      10: interface IHandler
      11: {
      12:     value: number;
      13:     callback : (result) => void;
      14: }
      15:  
      16: // costruttore di classe
      17:  
      18: class MyHandler implements IHandler
      19: {
      20:     value: number;
      21:  
      22:     constructor(public callback: (result) => void)
      23:     {}
      24: }

    In ordine di apparizione, nel primo esempio viene utilizzato un parametro denominato "callback" che è richiesto sia una funzione che accetta un parametro "result" ("any" visto che è omessa la dichiarazione di tipo) e non ritorna alcun valore. Nel secondo esempio invece abbiamo la definizione di una interfaccia che accetta una proprietà numerica e una seconda proprietà "callback" che richiede una function. Infine nel terzo esempio di da implementazione alla precedente interfaccia con una classe. In questo caso il metodo callback verrà fornito nel costruttore e la keyword public sul parametro da automaticamente implementazione alla proprietà pubblica (e questo basta per soddisfare l'interfaccia).

    Parametri opzionali

    Un problema ricorrente nella definizione di metodi sono i parametri opzionali. E' tipico, soprattuto di Javascript, l'avere funzioni i cui parametri non forniti sono automaticamente valorizzati a "null" e quindi con un semplice controllo è possibile simulare l'overloading che esiste nei linguaggi di più alto livello. In Typescript l'overloading dei metodi non esiste, se non nelle dichiarazioni delle interfacce, ma vige invece la possibilità di definire opzionali alcuni o tutti i parametri. Partendo da questa ultima abbiamo:

       1: function addItem(name: string, value?: number): void
       2: {
       3:     if (value == null)
       4:         value = 0;
       5: }

    L'indicazione di un "?" dopo il nome del parametro lo rende opzionale. E' chiaro che a questo punto abbiamo l'onere di verificare che esso sia valorizzato per evitare errori. Nell'esempio il parametro "value" viene valorizzato con un valore di default nel caso non sia stato specificato.

    La cosa interessante è che possiamo fare uso delle interfacce per simulare l'overload del metodo, fornendo una descrizione nell'intellisense che è di grande aiuto per lo sviluppatore. Prima di tutto dichiariamo una classe con il precedente metodo:

       1: class List
       2:     implements IList
       3: {
       4:     addItem(name: string, value?: number): void
       5:     {
       6:         if (value == null)
       7:             value = 0;
       8:     }
       9: }

    A questo punto, nell'interfaccia IList possiamo dare la definizione di due metodi con il medesimo nome. Attenzione che questa operazione nella classe darà adito ad un errore di compilazione mentre è perfettamente ammessa nell'interfaccia:

       1: interface IList
       2: {
       3:     addItem(name: string): void;
       4:     addItem(name: string, value: number): void;
       5: }

    In seguito a questa dichiarazione potremmo sfruttare l'interfaccia e l'intellisense di Visual Studio 2012 ci fornirà una descrizione del tutto simile a quella cui siamo abituati con C#:image

     

     

     

    Conclusione

    Il ridotto numero di tipi disponibile in Typescript non deve trarre in inganno. Così come in Javascript siamo in grado di trattare qualunque tipo abbastanza semplicemente, tanto più in Typescript saremo in grado di gestire agilmente qualunque informazione, con il supporto di una libreria di classi che sopperisce alla ristrettezza di tipi primitivi. E' il caso ad esempio del tipo "Date" che, come accade in Javascript, non è nativo del linguggio. Nella libreria automaticamente linkata dal compilatore troviamo le definizioni del tipo in termini di interfaccia e possiamo gestire correttamente il tipo in questione.


    Pur se lo static type checking è un elemento importante nell'utilizzo di Typescript, tanto da essere già una ragione più che valide nella sua adozione, è chiaro che si può fare di più nella semplificazione del codice Javascript e nella sua organizzazione. Nel corso degli anni si sono consolidate alcune pratiche comuni nella stesura di Javascript, per venire incontro alla carenza dei concetti di base dell'object orientation che sono particolarmente labili e limitati. Tra essi si possono annoverare alcune naming convention - ad esempio prependere un underscore ad una variabile la identifica come privata - e dei veri e propri pattern quali le closure. Tutto ciò in effetti è più che altro una notazione stilistica che una vera e propria caratteristica del linguaggio e spesso e volentieri tali pratiche tendono a renderlo di difficile comprensione e manutenzione. Typescript ha tra i suoi costrutti alcuni che hanno proprio lo scopo di semplificare nettamente il codice mascherando la vera e propria complessità che origina dalla sua compilazione.

    Interfacce e classi

    Nel precedente articolo abbiamo visto che grazie allo structured typing, Typescript è in grado di riconoscere i tipi semplicemente analizzando la corrispondenza delle proprietà. L'esempio seguente riassume in breve la questione:

       1: function getArea(s: { width: number; height: number; }): number
       2: {
       3:     return s.width * s.height / 2;
       4: }
       5:  
       6: var area = getArea({ width: 20, height: 30 });
       7: console.log(area.toString());

    E' del tutto chiaro che questo tipo di notazione, pur se tutelata dal compilatore, è eccessivamente prolissa e a lungo andare puà essere oggetto di errori e incomprensioni. Per questa ragione Typescript ammette innanzitutto la creazione di interfacce, che altro non sono che la definizione del contratto di un tipo, cui il valore deve conformarsi. Un concetto più che normale per chi mastica programmazione ad oggetti. Vediamo un esempio:

       1: interface Shape
       2: {
       3:     width: number;
       4:     height: number;
       5: }
       6:  
       7: function calculateArea(s: Shape): number
       8: {
       9:     return s.width * s.height  / 2;
      10: }
      11:  
      12: var area = calculateArea({ width: 20, height: 30 });
      13: console.log(area.toString());

    Nelle prime righe dello snippet è visibile la dichiarazione di una interfaccia "Shape". Essa riporta le proprietà "width" e "height" e viene usata come parametro della funzione calculateArea, al posto della precedente notazione estesa. L'argomento passato alla calculateArea è rimasto invariato, ma se provate a modificarne i nomi vi renderete contro che lo structured typing continua a funzionare come prima, validando il parametro contro la definizione dell'intefaccia. Le interfacce ammettono anche metodi e proprietà opzionali (usando il ?). Ecco un esempio:

       1: interface Shape
       2: {
       3:     width: number;
       4:     height: number;
       5:     color?: string;
       6:     getArea(): number;
       7: }
       8:  
       9: function calculateArea(s: Shape): number
      10: {
      11:     return s.getArea();
      12: }
      13:  
      14: var area = calculateArea(
      15:     {
      16:         width: 20,
      17:         height: 30,
      18:         getArea: function() { return this.width * this.height / 2; }
      19:     });
      20:  
      21: console.log(area.toString());

    L'esempio in questione estremizza la definizione dell'interfaccia Shape richiedendo una proprietà opzionale "color" (che poi non viene passata più sotto) e un metodo che effettua il calcolo dell'area. In tal modo la funzione calculateArea non deve fare altro che chiamare il metodo getArea dell'interfaccia per ottenere il valore calcolato. Si tratta di un primo passo verso una conversione object oriented dell'esempio. A questo punto potremmo voler implementare l'interfaccia Shape in diverse figure e fornire una diversa formula per il calcolo. Lo possiamo fare grazie alla presenza delle classi. Vediamo come:

       1: interface Shape
       2: {
       3:     width: number;
       4:     height: number;
       5:     getArea(): number;
       6: }
       7:  
       8: class Triangle implements Shape
       9: {
      10:     constructor(
      11:         public width: number,
      12:         public height: number) { }
      13:  
      14:     getArea(): number {
      15:         return this.width * this.height / 2;
      16:     }
      17: }
      18:  
      19: class Square implements Shape
      20: {
      21:     constructor(
      22:         public width: number,
      23:         public height: number) { }
      24:  
      25:     getArea(): number {
      26:         return this.width * this.height;
      27:     }
      28: }
      29:  
      30: function calculateArea(s: Shape): void
      31: {
      32:     var area = s.getArea();
      33:     console.log(area.toString());
      34: }
      35:  
      36: calculateArea(
      37:     new Square(20, 30));
      38: calculateArea(
      39:     new Triangle(20, 30));

    Grazie alla keyword "class" è possibile creare delle vere e proprie classi che, a differenza di quello che succede per le interfacce, che spariscono nel codice Javascript, generano una struttura che chi è avvezzo a Javascript riconoscerà sicuramente.

       1: var Triangle = (function () {
       2:     function Triangle(width, height) {
       3:         this.width = width;
       4:         this.height = height;
       5:     }
       6:     Triangle.prototype.getArea = function () {
       7:         return this.width * this.height / 2;
       8:     };
       9:     return Triangle;
      10: })();

    Nel precedente snippet abbiamo anche la dimostrazione che una classe può implementare una specifica interfaccia, per mezzo della keyword "implements" e così facendo il compilatore verificherà a tempo di compilazione che la classe supporti i metodi e le proprietà da essa richieste. Siamo a questo punto arrivati ad una programmazione ad oggetti del tutto raffinata, che poco ha a che vedere con la complessità cui si è abituati con Javascript, totalmente mascherata dal compilatore Typescript.

    Oltre all'implementazione di interfacce è del tutto possibile estendere classi esistenti. Per fare questo dovremo utilizzare la keywork "extends" al posto di "implements". Vediamo come usare l'ereditarietà per create una classe "Cube" derivando da "Square":

       1: class Cube
       2:     extends Square
       3: {
       4:     constructor(
       5:         width: number,
       6:         height: number,
       7:         public depth: number)
       8:     {
       9:         super(width, height);
      10:     }
      11:  
      12:     getArea(): number
      13:     {
      14:         return (super.getArea() * 2) +
      15:                (this.depth * this.width * 2) +
      16:                (this.depth * this.height * 2);
      17:     }
      18: }
    In questo esempio vediamo che al costruttore della classe viene aggiunto un ulteriore parametro "depth" che identifica l'altezza del parallelepipedo. Avendo modiificato la firma il compilatore richiede che la prima chiamata nel body del costruttore sia la funzione "super" che ha lo scopo di chiamare il costruttore della classe base. Questa deve essere specificata come faremmo usando "base" in C#. La medesima keyword può essere usata anche per chiamare i metodi della classe base. Ad esempio il metodo getArea richiama l'omonimo della classe base per poi sfruttare il risultato integrando la rimanente parte dell'area.

    Usare i moduli

    Una volta che abbiamo classi e interfacce i benefici che ne derivano sono numerosi, soprattutto in termini di organizzazione logica del codice e di manutenzione. Il passo successivo è di organizzare il codice in moduli - i programmatori C# li conosceranno meglio come "namespace" - per riuscire a creare vere e proprie librerie i cui nomi siano univoci. Anche in questo Typescript ci aiuta; grazie alla keyword "module" infatti sarà possibile creare dei veri e propri namespace:

       1: module Shapes
       2: {
       3:     export class Square implements Shape
       4:     {
       5:         constructor(
       6:             public width: number,
       7:             public height: number) { }
       8:  
       9:         getArea(): number
      10:         {
      11:             return this.width * this.height;
      12:         }
      13:     }
      14: }

    Interessante notare che la classe definita nel modulo "Shapes" è stata decorata con "export". Infatti, una volta che abbiamo messo una classe (o qualunque altro costrutto) in un modulo possiamo renderlo visibile o invisibile all'esterno beneficiando di un incapsulamento che in termini di librerie riutilizzabili è prezioso.

    Come si è abituati a fare con i namespace in C#, anche in Typescript i moduli possono essere annidati in modo del tutto analogo, creandoli effettivamente l'uno nell'altro:

       1: module Shapes
       2: {
       3:     export class Square implements Shape
       4:     {
       5:         constructor(
       6:             public width: number,
       7:             public height: number) { }
       8:  
       9:         getArea(): number
      10:         {
      11:             return this.width * this.height;
      12:         }
      13:     }
      14:  
      15:     export module ThreeD
      16:     {
      17:         export class Cube extends Square
      18:         {
      19:             // ... omissis
      20:         }
      21:     }
      22: }

    Oppure usando una notazione puntata

       1: module Shapes.ThreeD
       2: {
       3:     export class Cube extends Square
       4:     {
       5:         // ... omissis
       6:     }
       7: }

    Ciascuna delle due notazioni può essere tranquillamente utilizzata assieme all'altra creando vere e proprie composizioni in cui i moduli si combinano. Una volta che i moduli sono stati creati sarà possibile raggiungere i tipi definiti nei moduli specificando l'intero namespace:

       1: var square: Shapes.Square;
       2: var cube: Shapes.ThreeD.Cube;

    Data la notevole lunghezza e ridondanza che i nomi completi di namespace possono raggiungere è del tutto possibile creare degli shortcut che siano in grado di semplificare la scrittura del codice:

       1: import sh = Shapes;
       2: import sh3d = Shapes.ThreeD;
       3:  
       4: var square: sh.Square;
       5: var cube: sh3d.Cube;

    Come a casa propria

    Sono convinto che i programmatori C#, ma in generale qualunque sviluppatore sia avvezzo all'uso di un linguaggio evoluto basato sui paradigmi della programmazione ad oggetti, leggendo il codice Typescript si senta bene come a casa propria. In effetti se si da uno sguardo veloce al codice generato dal compilatore si comprende come Typescript sia in grado di fornire strumenti che la programmazione Javascript può dare solo a caro prezzo. Per intenderci vediamo un esempio di cosa sia possibile fare:

       1: module Shapes
       2: {
       3:     export interface Shape
       4:     {
       5:         width: number;
       6:         height: number;
       7:         getArea(): number;
       8:     }
       9:  
      10:     export enum ShapeType
      11:     {
      12:         Square,
      13:         Triangle
      14:     }
      15:  
      16:     export class ShapeFactory
      17:     {
      18:         static create(type: ShapeType, width: number, height: number): Shape
      19:         {
      20:             switch (type)
      21:             {
      22:                 case ShapeType.Square:
      23:                     return new Square(width, height);
      24:                 case ShapeType.Triangle:
      25:                     return new Triangle(width, height);
      26:             }
      27:  
      28:             return null;
      29:         }
      30:     }
      31:  
      32:     class Triangle implements Shape
      33:     {
      34:         constructor(
      35:             public width: number,
      36:             public height: number) { }
      37:  
      38:         getArea(): number
      39:         {
      40:             return this.width * this.height / 2;
      41:         }
      42:     }
      43:  
      44:     class Square implements Shape
      45:     {
      46:         constructor(
      47:             public width: number,
      48:             public height: number) { }
      49:  
      50:         getArea(): number
      51:         {
      52:             return this.width * this.height;
      53:         }
      54:     }
      55: }
      56:  
      57: import sh = Shapes;
      58: var sq = sh.ShapeFactory.create(sh.ShapeType.Square, 20, 30);
      59: console.log(sq.getArea());
    Credo che la combinazione di moduli, classi, interfacce ed enumeratori di questo esempio, assieme con l'applicazione di metodi statici e dell'incapsulamento nei moduli sia molto significativa di come si possa scrivere con proprietà un codice molto efficace.

    Mi è stato segnalato che talvolta il debug di typescript sembra non funzionare. ll debugger mostra i breakpoint con il classico pallino bianco anzichè con quello rosso pieno, ad indicare che non è in grado di trovare le informazioni di debug.

    Il problema è capitato a me stesso e sono arrivato a comprenderne la ragione, almeno quella relativa la mia problematica. Per fare in modo che il debug funzioni correttamente è necessrio referenziare il file "non minimizzato" nella pagina html. Infatti la mappa generata dal compilatore (il file .map) fa riferimento a questo file. Se invece, come ho fatto io referenziate il file ".min.js" Visual Studio non è in grado di trovare la corrispondenza e il debug non funziona.

    A questo punto rimane però il dubbio... dato che non esistono direttive di compilazione che si possano applicare all'HTML, come faccio a referenziare il file ".min.js" al momento del deploy della release?


    Se mi guardo indietro mi vedo, numerosi anni fa, seduto sulla panchina del binario 3 della stazione di Venezia Mestre - probabilmente in attesa del treno che mi portava al lavoro - mentre leggo avidamente di un interessante linguaggio che Netscape aveva realizzato e Microsoft aveva introdotto in Internet Explorer 3.0; tale Javascript. La lettura, del tutto tecnica e didascalica ebbe la capacità di svegliare quelle attenzioni per le questioni "Rich Internet" che tutt'oggi mi accompagnano in varie esperienze.

    Javascript, infatti, fu allora la risposta alle necessità che fin da subito permearono l'esperienza dello sviluppo di applicazioni web, in cui il gap nella user experience era talmente ampio rispetto quella della classiche applicazioni desktop da risultare indigesto ai più. Poter in qualche modo accedere alla dinamicità della pagina sul client e migliorare l'interazione con l'utente, era una necessità sentita e in qualche modo Javascript, in compagnia di DHTML, apriva un barlume di speranza.

    Paradossalmente, oggi a distanza di almeno 17 anni da allora - in termini informatici almeno un paio di ere geologiche - Javascript è assurto al linguaggio per eccellenza, non esclusivamente dedicato allo sviluppo "rich" ma ormai con ampi spazi anche server-side. Dopo essere passati per numerose esperienze, che hanno visto alti e bassi, corsi e ricorsi, parziali abbandoni e ritorni, alla fine l'unico vero linguaggio che può vantare l'aggettivo "cross-platform" è Javascript.

    Ma nonostante la longevità, anche nella sua più recente standardizzazione che va sotto il nome di EcmaScript 5.0, Javascript soffre dei problemi tipici dei linguaggi di scripting. In particolare la mancanza di tipi e la sua peculiare visione dell'object-orientation che omette concetti importanti quali l'incapsulamento e l'ereditarietà. A causa di questi problemi, nello sviluppo di applicazioni reali Javascript diventa un linguaggio ostico e, troppo spesso, pericoloso per la sua capacità di digerire qualunque cosa salvo poi scoppiare nel momento peggiore e cioè dopo il rilascio in produzione.

    Dn163601.78CFF275500F1DB4436598BF65141A6A(it-it,MSDN.10).png

    E' questa la ragione per cui molti si stanno orientando ad un nuovo tipo di strumenti, che abbia la capacità di tutelare lo sviluppatore mediante la type-safety e una programmazione object oriented vera, senza però perdere tutti gli indiscutibili vantaggi di Javascript con il cross-platform in testa a tutti. Microsoft in questo campo si sta muovendo rapidamente con la presentazione di un nuovo linguaggio denominato Typescript, giunto oggi alla versione 0.8.2.

    Pur trattandosi di una preview e omettendo ancora molti costrutti che uno sviluppatore normalmente si potrebbe aspettare, Typescript è un linguaggio sofisticato che ha la preziosa caratteristica di estendere Javascript, senza però richiedere un "interprete" nuovo nel browser, perchè il risultato della sua compilazione è Javascript. Un sorgente Javascript è a tutti gli effetti un sorgente Typescript perfettamente valido. Un sorgente Typescript genera comunque e sempre un sorgente Javascript valido. La parte del leone la fanno qui il compilatore "tsc.exe" e l'IDE di sviluppo, che anche se non necessariamente deve essere Visual Studio 2012, qualora lo si utiizzi è in grado di portare l'esperienza di sviluppo a livelli del tutto paragonabili a quelli che si hanno con linguaggi di alto livello come C#.

    Ma andiamo con ordine: le prime prove con Typescript si possono già fare online nel playground. Il compilatore Typescript infatti è scritto in Typescript - per inciso è anche open source - perciò è in grado di girare perfettamente all'interno del browser e in questa pagina è possibile scrivere, compilare e provare le prime righe di questo linguaggio, vedendone al contempo il risultato in termini di javascript prodotto. In alternative è possibile scaricare i tool per Visual Studio e avere così una esperienza integrata, garantita da alcuni template e da un editor suddiviso in due aree che mostrano assieme sorgente e compilato.

    Possiamo quindi sperimentare facilmente, e per farlo proviamo ad immettere il seguente codice nell'editor online oppure se preferite in Visual Studio 2012:

       1: function calculateHypotenuse()
       2: {
       3:    var c1 = 5;
       4:    var c2 = '2';
       5:    var hy = Math.sqrt(c1 * c1 + c2 * c2);
       6:    alert(hy);
       7: }

    Ad un occhio attento appare evidente che, purtrattandosi di codice perfettamente legale per Javascript, esso poi genererà un errore di runtime dovuto al fatto che il valore di c2 è impostato come una stringa invece che come un valore numerico, richiesto dalla funzione Math.sqrt(). Inoltre, un po' meno evidente ma anch'esso sorgente di un ulteriore errore, il valore hy ritornato è un numerico e non può essere passato direttamente alla funzione alert() che richiede una stringa. Il codice così com'è incollato nell'editor di Visual Studio ci metterà immediatamente in guardia proprio a causa dei suddetti problemi:

    Dn163601.8B3D2FD3F499553C04C1E790E9A91B60(it-it,MSDN.10).png

    Visual Studio 2012, mediante le sottolineature in rosso evidenzia il problema, pur trattandosi di codice Javascript senza alcun costrutto particolare di Typescript.

    Il compilatore Typescript infatti è in grado di inferire il tipo delle variabili dal loro utilizzo e di conseguenza segnala l'anomalia. Ovviamente, nella parte laterale, il codice Javascript non sarà generato ma sarà sostituito da un commento che riporta gli errori riscontrati.

    Piuttosto che correggere semplicemente gli errori, lavorando con typescript, però possiamo blindare il codice dichiarandone i tipi.

    Qui sotto vediamo il codice modificato e possiamo notare che a questo punto l'errore, visualizzato da Visual Studio, si è spostato nel punto, più opportuno, in cui avviene l'assegnazione. Il tooltip stesso evidenzia la causa dell'errore molto chiaramente. Poco sotto, parzialmente nascosto dal tooltip, viene usato toString() per fornire una stringa ad alert.

    Dn163601.87DF99060FE245829E025F8DB6D090ED(it-it,MSDN.10).png

    La sintassi di Typescript è piuttosto semplice e leggera rispetto a javascript, lasciando per quanto possibile inalterato il codice originario. Il proposito del team è di mantenere per quanto possibile una compatibilità con lo standard Ecmascript 6.0 in corso di definizione, così da mantenere sempre inalterato il paradigma che sostiene che un sorgente Javascript è un Typescript valido. Una volta corretto l'ultimo errore nell'esempio avremo finalmente un output Javascript come segue:

       1: function calculateHypotenuse() 
       2: {
       3:      var c1 = 5;
       4:      var c2 = 2;
       5:      var hy = Math.sqrt(c1 * c1 + c2 * c2);
       6:      alert(hy.toString());
       7: }

    Questo esempio banale, è però significativo e dà la misura di come, grazie al supporto di uno strumento di sviluppo quale il compilatore e in parte dell'IDE di Visual Studio 2012 in grado di sfruttarlo opportunamente, saremo in grado di scrivere codice di qualità che tuteli il nostro operato evitando che i normali errori si presentino nei momenti meno opportuni.

    Typescript contiene una serie di altre feature molto importanti, come la definizione di interfacce e tipi custom, che lo arricchiscono di una espressività che spesso è limitata dai costrutti molto arzigogolati di Javascript. Spesso tali feature sono del tutto sostitutive e simulano a compile time feature che Javascript non include. E' il caso ad esempio dei metodi e delle proprietà private che, pur non essendo supportate da Javascript in alcun modo, in Typescript trovano applicazione e un eccellente supporto di intellisense in Visual Studio 2012. Il codice compilato naturalmente perderà questa caratteristica ma solo dopo che essa ha perso la sua utilità.


    Il webcast di ieri è oramai passato ed è giunto il momento di pubblicare gli esempi di codice. Abbiamo avuto qualche problema tecnico, i partecipanti non erano molti come speravo, ma tutto sommato è andato bene. Un grazie a tutti coloro che hanno partecipato online e che mi hanno posto qualche domanda.

    Link: http://blog.boschin.it/download/Silverlight-Scripting.zip

    Technorati tags: , ,

    Scrivere codice in Javascript richiede anche il sobbarcarsi l'onere di contenere le dimensioni di quanto si sta scrivendo. Sarebbe fantastico poter scrivere classi su classi, strutturare al meglio l'applicazione, seguire delle prolisse convenzioni di naming, però alla fine quello con cui sempre dobbiamo fare i conti è la banda e la quantità di dati da trasferire che se sottovalutata potrebbe rendere inutilizzabili le nostre applicazioni.

    Qualche volta però basta un po' ingegnaarsi per riuscire a risparmiare un po' di codice e ottenere un risultato più che accettabile. A me ad esempio è successo esponendo eventi custom su dei controlli client derivati da Sys.UI.Control. Quando si espone un event capita spesso di dover allegare ad esso una classe Sys.EventArgs per fornire all'handler notifica di dettagli dell'evento. Nauralmente è sempre possibile estendere Sys.EventArgs per fornire delle proprietà aggiuntive e i relativi metodi get e set tuttavia questo comporta usare parecchie righe di codice la cui utilità è piuttosto limitata.

    Utilizzando expando però è molto semplice fare un po' di economia. Grazie ad esso possiamo facilmente "attaccare" proprietà, metodi e quant'altro a oggetti già esistenti.

    ... var args = new Sys.EventArgs(); args.myCustomData = "dati..."; ...

    Inutile creare una classe che estenda EventArgs. E' sufficiente appendere ad essa le proprietà che ci servono e risparmieremo un bel po' di bytes.

    Technorati tags: , ,

    Ci ho messo un po' a decidere come intitolare questo post, e alla fine ho optato per questo titolo alla Wertmuller perchè mi sembra che il succo del post che sto scrivendo sia proprio questo: imparare ad organizzare per bene il codice di scripting che come ho già detto più volte ha la spiacevole abitudine di infestare le pagine.

    L'idea che vorrei presentare mi è venuta lavorando con la Microsoft AJAX Library, e in breve è diventata il mio modo standard di approcciare lo sviluppo in Javascript su pagine HTML perchè mi consente di lavorare con una sorta di codebehind in cui ragruppo tutto il codice di scripting. La base per poter raggiungere questo scopo è una classina che mi sono scritto in -Javascript:

    Type.registerNamespace('Elite'); Elite.Page = function() { this.onload$delegate = Function.createDelegate( this, function(eventData) { this.load(); }); this.onunload$delegate = Function.createDelegate( this, function(eventData) { this.unload(); }); window.onload = this.onload$delegate; window.onunload = this.onunload$delegate; Elite.Page.initializeBase(this, [window]); } Elite.Page.prototype = { initialize : function() { Elite.Page.callBaseMethod(this, 'initialize'); }, load : function() { }, unload : function() { }, dispose : function() { if (this.onload$delegate) delete this.onload$delegate; if (this.onunload$delegate) delete this.onunload$delegate; Elite.Page.callBaseMethod(this, 'dispose'); } } } Elite.Page.registerClass('Elite.Page', Sys.UI.Control);

    La classe che ho realizzato dovrà essere utilizzata come base per la classe che rappresenta la pagina. Al suo interno infatti sono stati realizzati una serie di metodi stub che ricalcano il funzionamento normale di una pagina asp.net. Troviamo ad esempio il metodo load() che viene collegato automaticamente all'evento window.onload enaturalmente anche la controparte unload().

    Ecco come procedere se si vuole utilizzare questa tecnica in una propria pagina che poniamo si chiami dashboard.aspx:

    1) create un file Javascript denominato dashboard.aspx.js. questo consente di tenere i file a scelta in una stessa cartella e reperirli facilmente oppure affiancarli alla pagina e vederli nel solution explorer accanto al codebehind. Al termine dello sviluppo se fate uso del Web Application Project potreste convertire tutti gli script in risorse embedded e caricali con webresource.axd.

    2) includere il file javascript contenente la classe Elite.Page (ad esempio page.js). Dato che è obblgatorio fare uso della Microsoft AJAX Library è opportuno mettere la referenza all'interno dello ScriptManager che vi ricordo essere il luogo di elezione per qualsivoglia script.

    3) nel file dashboard.asp.js creare una classe che rappresenti la pagina e erediti dalla classe Elite.Page. Ecco un esempio:

     

    Type.registerNamespace('MyApplication'); MyApplication.DashboardPage = function() { MyApplication.DashboardPage.initializeBase(this, [window]); } MyApplication.DashboardPage.prototype = { load : function() { this.bSave = $get('bSave'); MyApplication.DashboardPage.callBaseMethod(this, 'load'); } }; MyApplication.DashboardPage.registerClass('MyApplication.DashboardPage', Elite.Page);

     

    La particolarità di questa classe è di "registrare" il controllo bSave usando $get(). L'evento load() è il posto migliore per questo genere di attività dato che vi si arriva subito dopo che il download e il rendering della pagina è stato effettuato.

    4) Inserire mediante ScritpManager.RegisterStartupScript() il codice che istanzia la classe:

    var currentPage = $create(MyApplication.DashboardPage, {}, {}, null, null);

    Questa chiamata in particolare istanzierà la classe e inizierà il ciclo di vita invocando il metodo initialize. Poi non appena caricata la pagina sarà invocato il metodo load() e di conseguenza la referenza verrà valorizzata con il controllo bSave. Naturalmente a questo punto sarà opportuno agganciare via script gli eventi dei controlli. Vi ricordo che per fare questo  è necessario l'uso di Function.createDelegate() che come ho già consente di mantenere il contesto di partenza e quindi di rimanere all'interno della classe.

    Rimane solo un problema. Sappiamo tutti che i controlli di ASP.NET hanno un id generato a runtime che può essere semplice o composto. Per questo vi sarà necessario passare come argomenti della classe gli id estratti dai ClientID. In realtà ho un'altra idea in incubazione ma... questo sarà l'argomento di uno dei prossimi post.


    Giusto ieri ho scritto due righe a proposito di programmazione object-oriented in Javascript e oggi voglio tornare sull'argomento per fare un ulteriore passo verso un lavoro corretto e produttivo. Noi tutti quando scriviamo in C# o in un qualunque linguaggio realmente object oriented siamo abituati a gestire eventi asincroni nel contesto stesso in cui questi sono generati in modo tale che la loro invocazione e la loro gestione rimanga confinata all'interno di una sola istanza di una classe. In Javascript invece, questo non è immediatamente possibile; Spesso e volentieri ci si trova a dover gestire chiamate asincrone, o eventi generati dall'interfaccia e utilizzando un paradigma object oriented ci si trova a gestire eventi fuori del contesto dal quale essi sono generati. Mi rendo conto che spiegare a parole questo problema è difficile perciò vi propongo un esempio che chiarisca. Poniamo ad esempio di voler scrivere una classe che sia in grado di trasformare un elemento dell'interfaccia in un pulsante. Ad essa sarà passato in ingresso un elemento del DOM ed essa sarà in grado di agganciare l'evento onclick e gestirlo quando necessario:

       1: // HTML
       2:  
       3: <div id="myButton">Click Me!!!</div>
       4:  
       5: // Classe Javascript
       6:  
       7: ClickButton = function(message, element)
       8: {
       9:     this._message = message;
      10:     element.onclick = this._onclick;
      11: }
      12: ClickButton.prototype = 
      13: {
      14:     _onclick : function()
      15:     {
      16:         alert(this._message);
      17:     }   
      18: }
      19:  
      20: // USO
      21:  
      22: var bt = new ClickButton("Ciao!!!", $get("myButton"));

    Guardando questo pezzetto di codice può sembrare tutto in perfetto ordine ma in realtà se provate a farlo girare in un qualsiasi browser il risultato sarà una message box con scritto "undefined" anzichè come ci si aspetterebbe un caloroso "Ciao!!!". Come dicevo pocanzi il problema è che Javascript non ha la nozione di contesto di una istanza, pur se noi passiamo ad essa un riferimento al metodo _onclick() in realtà stiamo semplicemente copiando in una variabile il corpo della funzione stessa che sarà completamente slegata dal contesto dell'istanza in cui si trova. Per ovviare a questo problema occorre passare all'evento non solo la funzione _onclick() ma anche un riferimento a "this" così che il runtime sia in grado di eseguirla correttamente. Per fare questo nella Microsoft AJAX Library esiste un metodo della classe statica "Function" che serve proprio a generare correttamente questa chiamata. Ecco come modificare la classe di cui sopra per farla funzionare:

       1: ClickButton = function(message, element)
       2: {
       3:     this._message = message;
       4:     element.onclick = Function.createDelegate(this, this._onclick);
       5: }
       6: ClickButton.prototype = 
       7: {
       8:     _onclick : function()
       9:     {
      10:         alert(this._message);
      11:     }   
      12: }

    Con createDelegate() verrà generata una funzione che ha appunto lacapacità di invocare il metodo richiesto nel contesto della classe di appartenenza. La definizione del metodo createDelegate() pur con questo nome un po' altisonante altro non è che uno stratagemma per memorizzare il riferimento a this:

       1: Function.createDelegate = function(instance, method)
       2: {
       3:     return function()
       4:     {
       5:         return method.apply(instance, arguments);
       6:     }
       7: }

    Chi ha provato ad usare Silverlight si sarà già imbattuto in qualcosa di analogo. In vari siti nella rete si trova la definizione di un metodo che è del tutto analogo a Function.createDelegate(). Ecco quindi un buon motivo per referenziare la Microsoft AJAX Library anche quando si lavora con Silverlight. Attenzione però che esiste almeno un evento che in Silverlight non potrete gestire con questo metodo. Si tratta dell'evento onResize dell'oggetto Host che tipicamente viene usato per riposizionare il layout al resize del controllo host.