Incapsulamento in JavaScript

Questo sarà il mio ultimo post nella serie “JavaScript for (C/)AL Developers” oggi. Se continuassi a bloggare su roba JavaScript quasi pura, potresti ragionevolmente chiedere se questo è in realtà un blog NAV o uno JavaScript. È ancora NAV, e mentre le cose di cui sto per scrivere sono puramente un concetto JavaScript, lo trovo molto rilevante per qualsiasi sviluppatore di componenti aggiuntivi di controllo. Quindi, tieni la mia birra, e porta con me un’altra.

Una delle lamentele che sento spesso su JavaScript è che in JavaScript non c’è incapsulamento. Questo è quasi completamente vero, tranne per il fatto che è completamente falso.

Dov’è il problema in primo luogo, e quindi qual è la soluzione? Tuffiamoci.

Il problema

Immagina di dichiarare un costruttore. Immagina per un secondo che siamo nel mondo ES5 (che sfortunatamente dobbiamo usare se vogliamo che i nostri componenti aggiuntivi di controllo siano pienamente compatibili con tutte le piattaforme su cui sono supportati sia NAV che Business Central).

Questo è il mio codice:

Ovviamente, questo mostra 42, che è la mia età attuale.

Presto sarà il mio compleanno, quindi questo sarebbe spettacolo 43:

Ora, mentre io vorrei assolutamente amore per essere in grado di fare qualcosa di simile nella vita reale:

… che non accadrà. In un mondo orientato agli oggetti decente, “age” dovrebbe essere una proprietà incapsulata e non dovresti essere in grado di chiamare vjeko.età = 25 a tutti. I linguaggi c# e “normali” orientati agli oggetti hanno un concetto di incapsulamento, possono gestirlo usando campi privati, ma JavaScript non ha alcun concetto di privato. Qualsiasi cosa definita su questo all’interno del costruttore di oggetti (o successivamente su un’istanza di un oggetto costruito) è completamente accessibile a tutto il codice che ha accesso a quell’istanza. Nel mio esempio sopra, chiunque può impostare l’età e farla franca.

Si potrebbe dire che JavaScript non ha incapsulamento. E come ho detto sopra, ti sbaglieresti completamente.

La soluzione

Per quanto sia ovvio che non possiamo dichiarare nulla come privato direttamente, ci sono ancora cose che possiamo usare. Un bel concetto che è utile è chiamato chiusure. Le chiusure sono spiegate a lungo su un milione di blog, siti di documentazione ed esempi di codice su Internet, e puoi google il bejesus da loro al tuo ritmo, quindi non approfondirò la spiegazione delle chiusure qui. Mi limiterò a saltare a destra in loro applicazione per risolvere il problema di incapsulamento.

Ci sono almeno due modi per gestirlo. Facciamo prima quello più ovvio: una funzione di accesso.

Immagina il mondo senza proprietà in cui non puoi fare oggetti.proprietà = valore (come vjeko.età = 25 nel nostro caso, per quanto mi piacerebbe assolutamente!). In quel mondo, avresti funzioni getter e setter:

(ignora per un momento il fatto che sto ancora usando questo.età per “incapsulare” la “proprietà”)

Ovviamente, saresti in grado di chiamarli in questo modo:

Quindi, se si desidera avere l’età in sola lettura, è sufficiente eliminare la funzione setAge setter. Se questo.l’età era davvero privata (che non lo è), questo farebbe il trucco per te. Il problema è che nulla di definito su questo è privato, è accessibile a chiunque abbia accesso a qualsiasi istanza dell’oggetto. E ‘ piu ‘ pubblico che mai.

Per risolvere questo problema, la prima cosa che dobbiamo fare è spostare la dichiarazione della funzione getter dal prototipo all’istanza. I membri Prototype sono più vicini a ciò che chiameremmo static in C#, anche se in runtime hanno determinati tratti comportamentali sia dei membri statici che dell’istanza. Tuttavia, spostiamo prima il membro dal prototipo e sull’istanza:

Questo risolve solo la prima parte del problema, il fatto che getAge è stato definito sul prototipo piuttosto che sull’istanza. Tuttavia, con un semplice cambiamento come questo:

… risolviamo il problema interamente:

L’età è ora completamente incapsulata. È possibile accedervi tramite la funzione getter, ma non è possibile impostarla direttamente perché è accessibile solo nell’ambito di chiusura di this.Funzione di istanza getAge.

Per attuare pienamente la Persona di classe, è necessario spostare il growOlder funzione dal prototipo in istanza:

E questo funziona esattamente come si desidera lavorare:

Ma perché funziona? Funziona a causa delle chiusure. Il parametro age del costruttore è stato catturato nell’ambito di chiusura delle funzioni getAge e growOlder, consentendo di accedere al suo valore da entrambe queste funzioni, ma rendendolo completamente inaccessibile a chiunque altro, in qualsiasi altro luogo.

Soluzione ancora migliore

Si potrebbe dire che non si desidera accedervi tramite una funzione getter e che si richiede una sintassi di proprietà di sola lettura in piena regola. Volete la vostra età di sola lettura e incapsulato allo stesso tempo. Preso! JavaScript non può incapsularlo! Tranne che è assolutamente possibile.

Ho affrontato l’Oggetto.defineProperty metodo nel mio post precedente, e se si legge che uno, si può immediatamente vedere come può essere applicato qui.

Quindi, definiamo una proprietà di istanza di sola lettura della classe Person:

Ecco. Non ha fatto male. E funziona:

Così il gioco è fatto. Incapsulamento in piena regola in JavaScript per aiutarti a scrivere codice buono e isolato e portare i tuoi componenti aggiuntivi di controllo al livello reale kick-a$ $.

Felice JavaScripting, e spero di avere più tempo per blog su altri suggerimenti e trucchi JavaScript interessanti e utili per gli sviluppatori (C/)AL.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.