2.35        JavaScript

JavaScript è un linguaggio interpretato creato dalla Netscape Communications nel 1994, col nome di LiveScript , per fornire al browser Navigator la possibilità di comportamento dinamico ed interattivo. JavaScript è stato supportato successivamente anche da Microsoft Explorer col nome di Jscript .

Sintatticamente Javascript è simile a Java, ma ne differisce per alcuni aspetti strutturali piuttosto importanti:

·         non è necessario dichiarare le variabili,

·         il tipo di dato è dedotto dal contenuto e dall’utilizzo (dynamic typing),

·         è possibile aggiungere alle classi proprietà e metodi a run time,

·         i sorgenti sono interpretati, quelli di Java sono compilati in bytecode.

JavaScript è un linguaggio ad oggetti in cui non c’è una rigida distinzione fra classi ed istanze, in luogo delle classi vi sono oggetti particolari detti prototipi (prototypical objects). Fra gli oggetti predefiniti ci sono stringhe, espressioni regolari, numeri, date, array e, visto il prevalente utilizzo del linguaggio, la pagina HTML (oggetto document). Gli oggetti hanno in genere un ampio repertorio di metodi, la figura Figura 2.35‑1 ne esemplifica qualcuno:

oggetto

Proprietà

Metodi

String

length

concat, replace, search, substr, split, slice, toLowerCase, toUpperCase, big, fontcolor, fontsize,...

Array

length

concat, join, pop, push, reverse, shift, slice, sort, ...

Date

 

getDate, getDay, getTime, getMonth, setDate, setTime, ...

Math

E, PI, LN2, ...

abs, pow, log, sin, cos, tan, random, sqrt, ...

document

bgColor, fgColor, title, forms[],...

write, handleEvent, ...

Figura 2.35 -1

L’istanza di un oggetto è un riferimento ad una funzione o prototipo, che di fatto ne è il costruttore: istanza = new nomeoggetto. I metodi sono le variabili presenti nella funzione nomeoggetto e dichiarate tramite la sintassi this.nomevariabile = nuovooggetto. Un oggetto erede è una funzione che è dichiarata istanza del progenitore: erede.prototype = new nomeoggetto.

Gli oggetti si basano su degli array associativi, infatti è accettato l’accesso alle proprietà ed ai metodi sia con la sintassi tipica degli oggetti, sia con quella degli array associativi: oggetto.proprietà e oggetto[proprietà]. Anche l’instanziazione di un oggetto può essere effettuata con la dichiarazione new oggetto o tramite istruzione di inizializzazione: nomeoggetto = {proprieta:valore,...}. Tuttavia gli oggetti creati con inizializzazione non sono prototipi, quindi non possono essere utilizzati per derivare nuovi oggetti.

Fra le istruzioni di controllo è presente l’assegnazione condizionale:

variabile = (condizione) ? valorepervero : valoreperfalso;

Esiste il goto, chiamato pudicamente continue; la gestione degli errori avviene intercettando l’istruzione tramite try {istruzione/i} e risolvendo l’errore mediante catch {istruzione/i}.

Un piccolo neo di Javascript è nella gestione dell’ambito delle variabili: all’esterno delle funzioni esse sono globali; le variabili interne alle procedure sono anch’esse globali, a meno di renderle locali tramite la dichiarazione var nomevariabile = ....

Non è possibile, nelle versioni eseguite dal browser, accedere al file system per motivi di sicurezza.

Javascript è stato standardizzato dall’ECMA (ECMA-262) con nome ECMAScript .

L’esempio che segue illustra l’utilizzo degli oggetti, l’aggiunto di un metodo alla classe predefinita DATE, e le diverse alternative di creazione di array ed oggetti.

<HTML>

<HEAD>

<TITLE>Esempio di JScript</TITLE>

<SCRIPT language=Javascript>

function lejour() {

  var mois=new Array("Janvier","Février","Mars","Avril","Mai","Juin",

                     "Juillet","Août","Septembre","Octobre","Novembre",

                     "Décembre");

  var jour=["Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi","Dimanche"];

  var Today = new Date;

  return jour[Today.getDay()-1]+ " " + Today.getDate() + " " +

         mois[Today.getMonth()] + " " + Today.getFullYear();}

  Date.leJour = lejour;      // aggiunto all'oggetto Date la funzione leJour

  function area() {

    var a = this.l1;

    var b = this.l2;

    var c = this.l3;

    var p = 0.5 * (a + b + c);

    return Math.pow(p*(p-a)*(p-b)*(p-c),0.5);}

  function triangolo(a,b,c) {

    this.l1 = a;

    this.l2 = b;

    this.l3 = c;

    this.area = area;}

  function equilatero(l) {

    this.l1 = l;

    this.l2 = l;

    this.l3 = l;

    this.h = 0.5 * Math.pow(3*l*l,0.5);}

  equilatero.prototype = new triangolo;        // prototipo figlio

</SCRIPT>

</HEAD>

<BODY bgcolor=silver>

<SCRIPT language=Javascript>       document.write("<CENTER>",(Date.leJour().bold()).fontcolor("red"),"</CENTER>");

   isoscele = {l1:3, l2:3,l3:4,ar:area,h:Math.pow(5,0.5)} // oggetto inizializ.

   document.write("<BR>isoarea: "+isoscele.ar()+"  h: "+isoscele["h"]);

   tr1 = new triangolo(3,4,5);             // oggetto istanziato

   document.write("<BR>area: "+tr1.area());

   tr2 = new equilatero(2);                // oggetto istanziato

   document.write("<BR>equiarea: "+tr2.area()+"  h: "+tr2.h);

</SCRIPT>

</BODY>

</HTML>

Lo script sottostante è un convertitore di formule in formato RPN (Revers Polish Notation).

<HTML>
  <HEAD>
    <TITLE>Esempio di JavaScript</TITLE>
    <script language=Javascript>
      patop = /\+|-|\*|\/|\^/;      // espr. regolare per operatori
      patpar = /\([^()]*\)/;        // espr. regolare per  ricerca parentesi
      patdigit = /^-?\d+\.?\d*/     // espr. regolare per  numeri segnati 
      function calcolo(formula,traccia) {
        document.write ("Espressione: "+formula + "<P>");     
        do {
           res = new String(formula.match(patpar)); // exstr. formule en parenthese
           if (res != "null") {
              // sostituisce all'espressione in parentesi il risultato
              formula = formula.replace(patpar,Polish(res.substr(1,res.length-2),traccia)); 
           }
        }
        while (res != "null");
        //str = "Risultato: "+Polish(formula,traccia);
        document.write(("Risultato: "+Polish(formula,traccia)).bold()); // valutazione residuo 
        document.write("<P><FORM ACTION=prjava.html><INPUT TYPE=SUBMIT VALUE=RITORNA></FORM>");
      }
      function printarray(nome,arr) {document.write("<BR>"+nome+": "+arr+"<BR>");}
      function preced(stack,op) {
          i = 0;
          while (i < stack.length)  {
            if (stack[i+1] == op) {
               stack[i] = stack[i]+" "+stack[i+2]+" "+stack[i+1]+" ";
               stack.splice(i+1, 2);
               }
               else i = i + 1;
          }
          return stack;
        }
        function Polish(formula,traccia) {
           // separazione operandi ed operatori
           stack = new Array();
           while (formula.length > 0)  {
                  if (patdigit.exec(formula)) {
                     resparray = patdigit.exec(formula);
                 stack.push(resparray[0]);    // operando
                 formula = formula.substr(resparray[0].length);  // elimino operando
                 if (patop.test(formula.substr(0,1))) {
                    stack.push(formula.substr(0,1));  // operatore
                    formula = formula.substr(1);                   
                 }
                 else if (formula.length > 0) return false;
              }
             else return false;
           }
          // determinazione precedenze
          stack = preced(stack,"^");
          stack = preced(stack,"*");
          stack = preced(stack,"/");
          stack = preced(stack,"+");
          stack = preced(stack,"-");    
          // valutazione stack
          if (traccia) printarray("RPN valuta",stack);
          stack = stack[0].split(/ /).reverse();
          rpn = new Array();   // stack valutation
          while (stack.length > 0) {
             itm = stack.pop();
             if (isNaN(itm)) {
                oper2 = rpn.pop();
                oper1 = rpn.pop();
                frm = (itm != "^") ? "ris = "+oper1+itm+oper2+";":
                                     "ris = Math.pow("+oper1+","+oper2+");";
                eval(frm);
                rpn.push(ris);
               }  
              else rpn.push(itm);                                    
            }
            return rpn.pop();      
        }
     </script>
 </HEAD>
 <BODY bgcolor=silver>
 <FORM name=forme>
 Introdurre la formula&nbsp;
 <input type=text value="(105-7*3*2+(12.5*4))-7^2" name=formula>
 <P>Traccia&nbsp;<input type=checkbox name=trace>
 <CENTER><P>
 <input type=button value="CALCOLA" onclick="javascript:calcolo(window.forme.formula.value,window.forme.trace.checked)">
 </CENTER>
 </FORM>
</BODY>
</HTML>