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.