Experimentalia

Appunti raminghi

Campi privati in Javascript

with 2 comments

Con la traduzione di quest’ultimo pezzo penso di concludere la serie di traduzioni dei testi presenti sul sito di Douglas Crockford. Si è trattato di pezzi interessanti che hanno coperto aspetti del linguaggio Javascript che solitamente misconosciuti. Almeno per me lo erano, e non potrò mai ringraziare abbastanza l’autore per averli scritti ed avermi concesso di pubblicarne la traduzione.

In questo post Crockford illustra la possibilità di utilizzare le chiusure per dotare gli oggetti Javascript di membri privati. Al solito non si limita a riportare un pattern di programmazione ma si sofferma sulla sua implementazione e sui meccanismi che gli stanno dietro.

Buona lettura.

Campi privati in Javascript

Titolo originale: Private members in JavaScript

Douglas Crockford (www.crockford.com)

Javascript è il linguaggio di programmazione più incompreso del mondo. Alcuni credono che non supporti l’incapsulamento delle informazioni perché gli oggetti non possono avere campi e metodi privati. Si tratta di un fraintendimento. Gli oggetti Javascript possono averer membri privati. Di seguito spiegherò come questo sia possibile.

Oggetti

Javascript è basato sugli oggetti. Gli Array sono oggetti. Le Funzioni sono oggetti. Gli Oggetti sono oggetti. In definitiva, cosa sono gli oggetti? Un Oggetto è una collezione di coppie nome-valore. I nomi sono stringhe, ed i valori possono essere stringhe, numeri, valori booleani o oggetti (inclusi vettori e funzioni). Gli oggetti sono solitamente implementati come tabelle hash in modo che i campi possano essere indirizzati rapidamente.

Se il valore è una funzione allora questa viene chiamata metodo. Quando viene invocato il metodo di un oggetto la variabile this referenzia l’oggetto. In questo modo, tramite this, il metodo potrà accedere alle variabili d’istanza.

Un Oggetto può essere creato da un costruttore, che è una funzione che inizializza oggetti. I construttori forniscono agli oggetti caratteristiche che in altri linguaggi sono conferite tramite classi, inclusi variabili statiche e metodi.

Public

I membri di un oggetto sono tutti metodi pubblici. Qualunque funzione può accedere, modificare o cancellare questi membri, o aggiungerne di nuovi. Ci sono due modi di aggiungere un membro ad un nuovo oggetto:

Nel costruttore

Questa tecnica viene solitamente usata per inizializzare le variabili pubbliche di istanza. La variabile this viene usata per aggiungere membri all’oggetto


    function Container(param) {
        this.member = param;
    }

In questo modo, se costruiamo un nuovo oggetto


    var myContainer = new Container('abc');

allora myContainer.member conterrà 'abc'.

Nel Prototipo

Questa tecnica si usa, solitamente, per aggiungere metodi pubblici. Quando un membro viene cercato inutilmente in un oggetto, viene usato il metodo del prototipo del costruttore dell’oggetto. L’ereditarietà viene garantita per delega. Questo sistema risparmia anche memoria. Per aggiungere un metodo a tutti gli oggetti creati tramite un costruttore, aggiungiamo una funzione al prototipo del costruttore (prototype):


    Container.prototype.stamp = function (string) {
        return this.member + string;
    }

In questo modo possiamo invocare il metodo


    myContainer.stamp('def');

che stampa 'abcdef'.

Membri Privati

I membri privati sono creati dai costruttori. I parametri e le variabili locali (dichiarate con var) diventano membri privati.


    function Container(param) {
        this.member = param;
        var secret = 3;
        var that = this;
    }

Questo costruttore crea tre variabili d’istanza private: param, secret e that. Queste vengono aggiunte all’oggetto ma non sono accessibili dall’esterno, e neanche dai metodi pubblici dell’oggetto. Sono accessibili solamente dai metodi privati. I metodi privati di un oggetto sono le funzioni nidificate all’interno del costruttore.


    function Container(param) {

        function dec() {
            if (secret > 0) {
                secret -= 1;
                return true;
            } else {
                return false;
            }
        }

        this.member = param;
        var secret = 3;
        var that = this;
    }

Il metodo privato dec esamina la variabile d’istanza secret. Se questa è maggiore di zero, la decrementa e restituisce true. In caso contrario restituisce false. Questo metodo può essere usato per creare oggetti utilizzabili solamente tre volte.

Per convenzione, creiamo un membro privato that. Questo viene utilizzato per permettere ai metodi privati di accedere all’oggetto che li contiene. Si tratta di uno stratagemma utile ad evitare un errore delle specifiche del linguaggio ECMAScript che attribuisce a this un valore sbagliato per le funzioni nidificate.

I metodo privati non possono essere chiamati dai metodi pubblici. Per rendere i metodi privati utili abbiamo bisogno di introdurre i metodi privilegiati.

Metodi Privilegiati

Un metodo privilegiato può accedere alle variabili private ed ai metodi, ed è visibile all’esterno, come ai metodi pubblici. E possibile eliminare o rimpiazzare un metodo privilegiato ma non è possibile modificarlo, o forzarlo a rivelare i propri segreti.

I metodi privilegiati sono assegnati con this all’interno del costruttore.


    function Container(param) {

        function dec() {
            if (secret > 0) {
                secret -= 1;
                return true;
            } else {
                return false;
            }
        }

        this.member = param;
        var secret = 3;
        var that = this;

        this.service = function () {
            if (dec()) {
                return that.member;
            } else {
                return null;
            }
        };
    }

service è un metodo privilegiato. MyContainer.service() restituirà 'abc' le prime tre volte che viene invocato. Dalla quarta volta in poi, restituirà null. Quando invocato, service chiama il metodo privato dec che, a sua volta, accede alla variabile privata secret. Il metodo service è raggiungibile dagli altri oggetti ed agli altri metodi ma non permette di accedere direttamente ai metodi privati.

Chiusure

Questo pattern di metodi pubblici, privati e privilegiati, è possibile perché Javascript supporta le chiusure. Questo significa che una funzione annidata ha sempre accesso alle variabili ed ai parametri della funzione che la incapsula anche se l’altra funzione ha terminato la propria esecuzione. Si tratta di una caratteristica del linguaggio estremamente potente. Attualmente non ci sono libri che si occupino di programmazione Javascript che mostrano come sfruttarla. Parecchi non la nominano nemmeno.

I membri privati e privilegiati possono essere creati solamente quando un oggetto viene creato. I metodi pubblici possono essere aggiunti in qualunque momento.

Pattern

Public

function Constructor(…) {

this.membername = value;

}

Constructor.prototype.membername = value;

Private

function Constructor(…) {

var that = this;

var membername = value;

function membername(…) {…}

}

Note: The function statement

function membername(…) {…}

is shorthand for

var membername = function membername(…) {…};

Privileged

function Constructor(…) {

this.membername = function (…) {…};

}

Copyright 2001 Douglas Crockford. All Rights Reserved Wrrrldwide.

Written by Eineki

novembre 27, 2009 a 6:59 am

2 Risposte

Subscribe to comments with RSS.

  1. REFUSI: (è diventato quasi un mestiere…)
    cancellari = cancellare
    construttore = costruttore
    inizializare = inizializzare
    aggiungere aggiungere un metodo a tuttu = aggiungere un metodo a tutti
    My 2 cents..
    Eineki edit
    Corretti gli errori, che ho per questo depennato dalla lista, grazie per l’impegno

    Daniele

    dicembre 15, 2009 at 22:21 pm

  2. Quello che viene illustrato nell’articolo è una “forzatura” del linguaggio, atta ad “emulare” la presenza di proprietà private. Ma il JavaScript, al momento, non supporta, di suo, proprietà e metodi privati, tant’è vero che il metodo sopra esposto determina un consumo di memoria aggiuntivo ogni volta che si crea un nuovo oggetto, essendo che il costruttore dovrà allocare nuova memoria per delle funzioni che, di fatto, son sempre le stesse. L’utilizzo dei prototipi, in JavaScript, serve proprio a risparmiare memoria, poiché, grazie ad essi, i metodi vengono definiti una volta sola, anche se si creano 10.000 oggetti di un certo tipo. Ma il metodo sopra esposto impedisce di usare il meccanismo dei prototipi, con tutte le conseguenze che ci si può aspettare. Riprendendo l’esempio dell’articolo, se io creassi 10.000 istanze di Container, l’interprete JavaScript dovrebbe allocare 10.000 oggetti di tipo function per il metodo privato “dec”, più altri 10.000 oggetti di tipo function per il metodo privilegiato “service”. Ricordiamo, infatti, che a differenza di altri linguaggi, in JavaScript, quando definisco una funzione, in realtà sto creando un oggetto speciale di tipo function, e pertanto alloco memoria per esso.

    Certo, un interprete particolarmente furbo potrebbe accorgersi che il corpo di una funzione è uguale identico a quello di un’altra già dichiarata in passato ed usare quindi un unico riferimento in memoria per esse. Ma nello scrivere codice efficiente non bisognerebbe basarsi sull’ipotesi che l’interprete faccia o meno determinate ottimizzazioni. Come disse quel tale: prevenire è meglio che curare.

    Fra l’altro, l’emulazione delle proprietà e metodi privati, rende il codice più difficile da capire (e, quindi, da manutenere).

    Morale della favola: il mio consiglio è quello di usare JavaScript nella maniera più semplice e diretta possibile, evitando forzature come quelle dell’articolo. L’utilizzo di metodi e proprietà private lo prenderei in considerazione solo quando il linguaggio ne permetterà l’uso in via ufficiale, tramite keyword apposite (che eviteranno gli sprechi di memoria sopra menzionati).

    Interessante notare, a tal proposito, che nelle specifiche ECMASCript, le keyword private, protected e public sono considerate riservate per un utilizzo futuro.

    Mauro

    maggio 28, 2013 at 2:27 am


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...

%d blogger cliccano Mi Piace per questo: