javascript-logo-bw

Appunti JavaScript

Una ottima guida è questa: http://killdream.github.com/blog/2011/10/understanding-javascript-oop/

Variable scope

Le variabili sono visibili nello scope della funzione in cui sono definite (eventualmente nello scope global). Non c’è un block statement:

// la variabile x è visibile al di fuori del blocco if: infatti lo scope è quello globale,
// non essendoci una funzione definita.
if (true) {
  var x = 5;
}
console.log(x);

Variabili Globali

Nelle pagine web l’ oggetto globale è l’ oggetto window: quindi le variabili di una finestra sono accessibili da altre finestre.

Function scope

Le variabili definite all’ interno di una funzione non sono accessibili dall’ esterno: sono membri privati.
Ma una funzione può accedere alle variabili e alle funzioni definite nello stesso scope in cui essa è definita:

  • Una funzione definita nello scope globale può accedere a tutti i membri globali
  • Una funzione definita all’ interno di una funzione può accedere a tutti i membri definiti nella funzione genitrice, e ai membri a cui la funzione genitrice ha accesso

Da questo comportamento deriva quello delle closures.

Closures

Le funzioni “esterne” non hanno accesso alle variabili definite nelle funzioni in esse annidate: è una sorta di protezione dei dati.
Una closure si realizza quando viene esposta all’ esterno una funzione interna, che sappiamo avere accesso alle variabili interne.

var pet = function(name) {          // Il parametro name definisce una variabile interna !!
      var getName = function() {
        return name;                // La funzione privata ha accesso alla variabile esterna "name"
      }

      return getName;               // Restituisce la funzione interna, esponendo la variabile "name"
    },
    myPet = pet("Vivie");

myPet();                            // Returns "Vivie"

Esempio più complesso: il costruttore ritorna un oggetto con 4 funzioni che realizzano alcune closures:

var createPet = function(name) {    // name è una variabile protetta
  var sex;                          // anche sex è una variabile protetta

  return {                          // Restituisce un oggetto definito tramite "object literals"
    setName: function(newName) {    // I membri restituiti sono pubblici !!!
      name = newName;
    },

    getName: function() {
      return name;
    },

    getSex: function() {
      return sex;
    },

    setSex: function(newSex) {
      if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
        sex = newSex;
      }
    }
  }
}

var pet = createPet("Vivie");
pet.getName();                  // Vivie

pet.setName("Oliver");
pet.setSex("male");
pet.getSex();                   // male
pet.getName();                  // Oliver

Object Literals vs. Constructed Objects

riterimento: http://www.zebrakick.com/object-literals-vs-constructed-objects-in-javascript/

Object literals – ogetti statici

La notazione object-literal definisce oggetti Singleton:

var OggettoStatico = {
    prop1: "val 1",
    prop2: "val 2"
};

var Oggetto2 = OggettoStatico;  // Ad Oggetto2 viene assegnato un riferimento ad OggettoStatico !!
console.log(OggettoStatico, Oggetto2); //({prop1:"val 1", prop2:"val 2"}) ({prop1:"val 1", prop2:"val 2"})
Oggetto2.prop2 = "altro";
console.log(OggettoStatico, Oggetto2); //({prop1:"val 1", prop2:"altro"}) ({prop1:"val 1", prop2:"altro"})

Gli oggetti statici possono essere utili per creare delle librerie senza utilizzare il global scope.

IMPORTANTE: tutti i membri definiti con notazione object-literals sono necessariamente pubblici.

Constructed objects – oggetti istanziati

Questo metodo è l’ unico ad offrirela posibiltà di definire membri privati grazie alle closure.
Si è già visto come dichiarare membri pubblici e privati, con this e var rispettivamente.

Un discorso a parte va fatto per i metodi privati: in essi this assume il valore Window

var oggetto = function() {
	var prv = function() { console.log(this); };
	this.cns = function() {
		prv.call();
	}
}

var xxx = new oggetto();
xxx.cns();           // Sulla console si avrà [object Window]

Un buon metodo per avere un riferimento all’ oggetto dall’ interno di un metodo privato è quello di dichiarare una variabile privata con un riferimento a this: il metodo privato può accedere a questa nuova variabile.

var oggetto = function() {
	var self = this;
	var prv = function() { console.log(self); };
	this.pub = "something";
	this.cns = function() {
		prv();
	}
}

var xxx = new oggetto();
xxx.cns();

Un altro metodo, che però non mi piace, è quello di definire una funzione pubblica che faccia da wrapper al metodo privato:

var oggetto = function() {
	var prv = function() { console.log(this); };  //metodo privato
	this.pub = "something";
	this.cns = function() {  //wrapper che chiama prv passandogli this
		prv.call(this);
	}
}

var xxx = new oggetto();
xxx.cns();

E’ interessante notare l’ output sulla console:

({pub:"something", cns:(function () {prv.call(this);})})

è un oggetto in notazione letterale, di cui vediamo i soli membri pubblici: prv non è riportato.

Classi con la notazione object-literal

riferimento: http://www.gabordemooij.com/jsoop.html

Vediamo ora come creare e gestire classi in javascript considerando solo la notazione object-literal, senza i prototipi delle classi.

Object oriented

A differenza di altri linguaggi, JS opera direttamente su oggetti, e non su classi.
In PHP o Java si scrivono le classi e poi si istanziano gli oggetti, in JS invece si scrive direttamente un oggetto.

Costruttore

Rimanendo in ambito object-literal, in cui ogni membro è necessariamente pubblico, possiamo pensare ad un factory method:

Cat = {
    createNew: function(){
        var cat = { "name":"Silvester" }
        return cat;
    }
}

questo metodo pubblico crea un oggetto cat e lo restituisce.

Classi

Approfondiamo l’ analisi: mancando le classi in JS, possiamo realizzare un oggetto per creare altri oggetti; questo oggetto è un builder.
Nel builder si possono aggiungere i membri:

Cat = {
    createNew: function() {
        var cat = {}; //create an empty object
        cat.makeSound= function(){ //add logic
            alert("meow");
        }
        return cat; //return the fabricate
    }
}

var cat = Cat.createNew();
cat.makeSound();

Membri privati

Come visto in precedenza, lo scope delle variabili all’ interno delle funzioni offre la protezione dei dati.
Quindi dichiarare variabili all’ interno del costruttore le rende “locali” ad esso:

Cat = {
    createNew: function() {
        var cat = {};
        var sound = "meow"; //sound is local
        cat.makeSound= function(){
            //can reach sound from here
            alert( sound );
        }
        return cat;
    }
}

var cat = Cat.createNew();
cat.makeSound();
// ma non possiamo accedere a sound direttamente:
alert(cat.sound); // undefined

Notare che se si aggiungono successivamente altri metodi privati, questi non possono accedere alle proprietà private anche se fanno parte dello stesso oggetto.

Ereditarietà

Bisogna chiamare il costruttore della classe genitrice:

Animal = {
    createNew: function() {
        var animal = {};
        animal.eat = function(){ alert("eating"); }
        return animal;
    }
}

Cat = {
    createNew: function() {
        var cat = Animal.createNew(); // Chiama il costruttore: abbiamo la classe genitrice
        var sound = "meow";
        cat.makeSound= function(){
            alert( sound );
        }
        return cat;
    }
}

var cat = Cat.createNew();
cat.makeSound();
cat.eat();

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...