AntonioGanci

Il blog di Antonio Ganci
posts - 201, comments - 420, trackbacks - 31

Accedere ad un field pubblico da un metodo privato in Javascript

Oggi mi sono imbattuto in un problema imprevisto e voglio condividerlo perché potrebbe tornare utile a chi non padroneggia Javascript.

Supponiamo di avere un oggetto definito come segue:

function AnObject() {
    this.value = 1000;
    
    var set_value = function(new_value) {
        this.value = new_value;
    };
    
    this.start = function() {
        set_value(5);
    }
}

L'oggetto ha un field pubblico chiamato value, un metodo pubblico chiamato start ed un metodo privato chiamato set_value. Supponiamo ora che vogliamo testarlo ed il test sia il seguente:

function an_object_test()
{
    test("an object", function() {
        var obj = new AnObject();
        
        obj.start();
        
        equal(obj.value, 5);    
    });
}

Il test sarà passerà o fallirà? Se lo eseguiamo otterremo una soprendente barra rossa, con il messaggio: Expected 5 but was 1000, come se il metodo privato non fosse stato eseguito. Per quale motivo?

Il this nel metodo privato non si riferisce all'oggetto AnObject, piuttosto all'oggetto globale del browser window. Questo problema è spiegato nel post Private Members in JavaScript di Douglas Crockford. In particolare la soluzione proposta è:

function AnObject() {
    this.value = 1000;
    var that = this;
    
    var set_value = function(new_value) {
        that.value = new_value;
    };
    
    this.start = function() {
        set_value(5);
    }
}

Il motivo del field that è spiegato nel post:

By convention, we make a private that variable. This is used to make the object available to the private methods. This is a workaround for an error in the ECMAScript Language Specification which causes this to be set incorrectly for inner functions.

Tenetelo presente quando lavorate in Javascript perché potrebbe riservare spiacevoli sorprese.

Print | posted on Monday, February 14, 2011 2:48 PM | Filed Under [ Tips ]

Feedback

Gravatar

# re: Accedere ad un field pubblico da un metodo privato in Javascript

Non sono un esperto di Javascript e ho fatto poche prove, ma, seguendo lo Yahoo module pattern, io avrei fatto una cosa del genere:

function AnObject() {
var value = 1000;

function start() {
set_value(5);
};

function set_value(new_value) {
value = new_value;
};

return {
get_value: function(){return value;},
start: start
};
};

il return in fondo pubblica start() e value (come AnObject.get_value()).
2/14/2011 5:43 PM | Riccardo
Gravatar

# re: Accedere ad un field pubblico da un metodo privato in Javascript

x Riccardo: un approccio interessante, non lo conoscevo. Proverò ad approfondire.

x Gian Marco: vorrei evitare l'uso di framework perché non padroneggio a sufficienza JavaScript e vorrei prima conoscerlo a fondo. Il pericolo che vedo nel partire da subito ad usare il framework è di non avere il controllo su cosa accade.
2/14/2011 7:47 PM | Antonio Ganci
Gravatar

# re: Accedere ad un field pubblico da un metodo privato in Javascript

Ciao Luca, scusa se rispondo con tutto questo ritardo..

Si, con l'utilizzo delle closure si possono simulare metodi e variabili pubbliche.
Per qualche tempo ho utilizzato questa tecnica, creavo le classi esattamente come riportato nel commento di Riccardo.

Ho però abbandonato questa tecnica per i seguenti motivi (in ordine di importanza che gli ho attribuito):

* Scarsa leggibilità: qualunque classe non banale risulta molto contorta.
* Ho realizzato che non ho l'esigenza di PROTEGGERE fields, ma ho l'esigenza di COMUNICARE che un field è inteso per uso interno, e per questo la naming convention è sufficiente.
* Impossibilità di stubbare/mockare field o metodi privati durante il testing (a volte fa comodo).
* Difficoltà nel debugging: con Firebug/Crome è molto comodo visualizzare i fields di una classe, molto piu scomodo è visualizzare le variabili in una closure (di fatto l'unico modo che conosco devi mettere un breakpoint nello scope).
* I parametri del costruttore rimangono in scope, quindi sono praticamente fields, anche se non li vuoi (in genere ci sta, ma non sempre).
* nessuna delle librerie per OOP in JS si basa su questa tecnica.
* Per gli oggetti creati in quel modo ogni ISTANZA contiene una copia dei metodi, questo appesantisce l'esecuzione nel caso si debbano creare molte istanze della stessa classe e potrebbe essere un problema di performances.


3/11/2011 7:26 PM | Gian Marco Gherardi
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET