Ho visto un paio di risposte simili, ma vorrei menzionare questo post descrive meglio, quindi mi piacerebbe condividerlo con te.
Ecco un po 'di codice preso da esso, che ho modificato per ottenere un esempio completo che si spera possa dare vantaggi alla comunità perché può essere usato come modello di progettazione per le classi.
Risponde anche alla tua domanda:
function Podcast() {
// private variables
var _somePrivateVariable = 123;
// object properties (read/write)
this.title = 'Astronomy Cast';
this.description = 'A fact-based journey through the galaxy.';
this.link = 'http://www.astronomycast.com';
// for read access to _somePrivateVariable via immutableProp
this.immutableProp = function() {
return _somePrivateVariable;
}
// object function
this.toString = function() {
return 'Title: ' + this.title;
}
};
// static property
Podcast.FILE_EXTENSION = 'mp3';
// static function
Podcast.download = function(podcast) {
console.log('Downloading ' + podcast + ' ...');
};
Dato questo esempio, puoi accedere alle proprietà / funzioni statiche come segue:
// access static properties/functions
console.log(Podcast.FILE_EXTENSION); // 'mp3'
Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...'
E l' oggetto proprietà / funzioni semplicemente come:
// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
Nota che in podcast.immutableProp (), abbiamo una chiusura : il riferimento a _somePrivateVariable è mantenuto all'interno della funzione.
Puoi persino definire getter e setter . Dai un'occhiata a questo frammento di codice (dove si d
trova il prototipo dell'oggetto per il quale vuoi dichiarare una proprietà, y
è una variabile privata non visibile al di fuori del costruttore):
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {return this.getFullYear() },
set: function(y) { this.setFullYear(y) }
});
Definisce la proprietà d.year
tramite get
e le set
funzioni: se non si specifica set
, la proprietà è di sola lettura e non può essere modificata (tenere presente che non si verificherà un errore se si tenta di impostarla, ma non ha alcun effetto). Ogni proprietà ha gli attributi writable
, configurable
(consentire ai cambiamenti dopo la dichiarazione) e enumerable
(permette di usarlo come enumeratore), che sono per impostazione predefinita false
. È possibile impostarli tramite defineProperty
nel terzo parametro, ad es enumerable: true
.
Ciò che è anche valido è questa sintassi:
// getters and setters - alternative syntax
var obj = { a: 7,
get b() {return this.a + 1;},
set c(x) {this.a = x / 2}
};
che definisce una proprietà leggibile / scrivibile a
, una proprietà di sola lettura b
e una proprietà di sola scrittura c
, attraverso la quale è a
possibile accedere alla proprietà .
Uso:
console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21
Appunti:
Per evitare comportamenti imprevisti nel caso in cui hai dimenticato la new
parola chiave, ti suggerisco di aggiungere quanto segue alla funzione Podcast
:
// instantiation helper
function Podcast() {
if(false === (this instanceof Podcast)) {
return new Podcast();
}
// [... same as above ...]
};
Ora entrambe le seguenti istanze funzioneranno come previsto:
var podcast = new Podcast(); // normal usage, still allowed
var podcast = Podcast(); // you can omit the new keyword because of the helper
L'istruzione "new" crea un nuovo oggetto e copia tutte le proprietà e i metodi, ad es
var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"
Si noti inoltre che in alcune situazioni può essere utile utilizzare l' return
istruzione nella funzione di costruzionePodcast
per restituire un oggetto personalizzato che protegge le funzioni su cui la classe si basa internamente ma che devono essere esposte. Questo è spiegato ulteriormente nel capitolo 2 (Oggetti) della serie di articoli.
Puoi dirlo a
ed b
ereditare da Podcast
. Ora, cosa succede se si desidera aggiungere un metodo al Podcast che si applica a tutti dopo a
e che b
è stato istanziato? In questo caso, utilizzare .prototype
quanto segue:
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
Adesso chiama a
e b
ancora:
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
Puoi trovare maggiori dettagli sui prototipi qui . Se vuoi fare più eredità, suggerisco di esaminare questo .
Le serie di articoli che ho menzionato sopra sono altamente raccomandate da leggere, includono anche i seguenti argomenti:
- funzioni
- Oggetti
- prototipi
- Applicazione di nuove funzioni per costruttori
- sollevamento
- Inserimento automatico punto e virgola
- Proprietà e metodi statici
Si noti che l' inserimento automatico del punto e virgola "funzione" di di JavaScript (come menzionato in 6.) è spesso responsabile di causare strani problemi nel codice. Quindi, preferirei considerarlo un bug piuttosto che una funzionalità.
Se vuoi leggere di più, ecco un articolo MSDN piuttosto interessante su questi argomenti, alcuni dei quali descritti forniscono ulteriori dettagli.
Ciò che è interessante da leggere (che coprono anche gli argomenti sopra menzionati) sono quegli articoli della Guida JavaScript MDN :
Se vuoi sapere come emulare i out
parametri c # (come in DateTime.TryParse(str, out result)
) in JavaScript, puoi trovare il codice di esempio qui.
Quelli di voi che lavorano con IE (che non ha una console per JavaScript a meno che non apriate gli strumenti di sviluppo usando F12e aprite la scheda della console) potrebbero trovare utile il seguente frammento. Ti permette di usare console.log(msg);
come usato negli esempi sopra. Basta inserirlo prima della Podcast
funzione.
Per comodità, ecco il codice sopra in uno snippet di codice singolo completo:
let console = { log: function(msg) {
let canvas = document.getElementById("log"), br = canvas.innerHTML==="" ? "" : "<br/>";
canvas.innerHTML += (br + (msg || "").toString());
}};
console.log('For details, see the explaining text');
function Podcast() {
// with this, you can instantiate without new (see description in text)
if (false === (this instanceof Podcast)) {
return new Podcast();
}
// private variables
var _somePrivateVariable = 123;
// object properties
this.title = 'Astronomy Cast';
this.description = 'A fact-based journey through the galaxy.';
this.link = 'http://www.astronomycast.com';
this.immutableProp = function() {
return _somePrivateVariable;
}
// object function
this.toString = function() {
return 'Title: ' + this.title;
}
};
// static property
Podcast.FILE_EXTENSION = 'mp3';
// static function
Podcast.download = function(podcast) {
console.log('Downloading ' + podcast + ' ...');
};
// access static properties/functions
Podcast.FILE_EXTENSION; // 'mp3'
Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...'
// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {
return this.getFullYear()
},
set: function(y) {
this.setFullYear(y)
}
});
// getters and setters - alternative syntax
var obj = {
a: 7,
get b() {
return this.a + 1;
},
set c(x) {
this.a = x / 2
}
};
// usage:
console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21
var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
<div id="log"></div>
Appunti:
Alcuni buoni consigli, suggerimenti e raccomandazioni sulla programmazione JavaScript in generale sono disponibili qui (best practice JavaScript) e lì ('var' contro 'let') . Inoltre è raccomandato questo articolo sui dattiloscritti impliciti (coercizione) .
Un modo conveniente per usare le classi e compilarle in JavaScript è TypeScript. Ecco un parco giochi dove puoi trovare alcuni esempi che mostrano come funziona. Anche se al momento non stai usando TypeScript, puoi dare un'occhiata perché puoi confrontare TypeScript con il risultato JavaScript in una vista affiancata. La maggior parte degli esempi sono semplici, ma c'è anche un esempio Raytracer che puoi provare all'istante. Consiglio in particolare di esaminare gli esempi "Uso delle classi", "Uso dell'ereditarietà" e "Uso dei generici" selezionandoli nella casella combinata: questi sono dei bei modelli che puoi usare istantaneamente in JavaScript. Typescript è usato con Angular.
Per ottenere l' incapsulamento di variabili locali, funzioni ecc. In JavaScript, suggerisco di utilizzare uno schema come il seguente (JQuery utilizza la stessa tecnica):
<html>
<head></head>
<body><script>
'use strict';
// module pattern (self invoked function)
const myModule = (function(context) {
// to allow replacement of the function, use 'var' otherwise keep 'const'
// put variables and function with local module scope here:
var print = function(str) {
if (str !== undefined) context.document.write(str);
context.document.write("<br/><br/>");
return;
}
// ... more variables ...
// main method
var _main = function(title) {
if (title !== undefined) print(title);
print("<b>last modified: </b>" + context.document.lastModified + "<br/>");
// ... more code ...
}
// public methods
return {
Main: _main
// ... more public methods, properties ...
};
})(this);
// use module
myModule.Main("<b>Module demo</b>");
</script></body>
</html>
Ovviamente, puoi - e dovresti - inserire il codice dello script in un *.js
file separato ; questo è solo scritto in linea per mantenere l'esempio breve.
Le funzioni di auto-invocazione (note anche come IIFE = Espressione di funzione immediatamente richiamata) sono descritte più dettagliatamente qui .