J'ai vu quelques réponses similaires, mais je voudrais mentionner que cet article le décrit le mieux, alors je voudrais le partager avec vous.
Voici un code qui en est tiré, que j'ai modifié pour obtenir un exemple complet qui, espérons-le, profite à la communauté car il peut être utilisé comme modèle de conception pour les classes.
Cela répond également à votre question:
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 + ' ...');
};
Dans cet exemple, vous pouvez accéder aux propriétés / fonctions statiques comme suit:
// access static properties/functions
console.log(Podcast.FILE_EXTENSION); // 'mp3'
Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...'
Et les propriétés / fonctions de l' objet sont simplement les suivantes:
// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
Notez que dans podcast.immutableProp (), nous avons une fermeture : La référence à _somePrivateVariable est conservée à l'intérieur de la fonction.
Vous pouvez même définir des getters et setters . Jetez un œil à cet extrait de code (où d
est le prototype de l'objet pour lequel vous souhaitez déclarer une propriété, y
est une variable privée non visible en dehors du constructeur):
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {return this.getFullYear() },
set: function(y) { this.setFullYear(y) }
});
Il définit la propriété d.year
via get
et set
fonctionne - si vous ne spécifiez pas set
, alors la propriété est en lecture seule et ne peut pas être modifiée (sachez que vous n'obtiendrez pas d'erreur si vous essayez de la définir, mais cela n'a aucun effet). Chaque propriété possède les attributs writable
, configurable
(permettent de changer après la déclaration) et enumerable
(permet de l' utiliser comme recenseur), qui sont par défaut false
. Vous pouvez les définir via defineProperty
dans le 3ème paramètre, par exemple enumerable: true
.
Ce qui est également valable, c'est cette syntaxe:
// getters and setters - alternative syntax
var obj = { a: 7,
get b() {return this.a + 1;},
set c(x) {this.a = x / 2}
};
qui définit une propriété lisible / inscriptible a
, une propriété en lecture seule b
et une propriété en écriture seule c
, à travers laquelle la propriétéa
est accessible.
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
Remarques:
Pour éviter un comportement inattendu au cas où vous auriez oublié le new
mot - clé, je vous suggère d'ajouter ce qui suit à la fonction Podcast
:
// instantiation helper
function Podcast() {
if(false === (this instanceof Podcast)) {
return new Podcast();
}
// [... same as above ...]
};
Désormais, les deux instanciations suivantes fonctionneront comme prévu:
var podcast = new Podcast(); // normal usage, still allowed
var podcast = Podcast(); // you can omit the new keyword because of the helper
La «nouvelle» instruction crée un nouvel objet et copie toutes les propriétés et méthodes, c.-à-d.
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"
Notez également que dans certaines situations, il peut être utile d'utiliser l' return
instruction dans la fonction constructeur Podcast
pour renvoyer un objet personnalisé protégeant les fonctions sur lesquelles la classe s'appuie en interne mais qui doivent être exposées. Ceci est expliqué plus en détail au chapitre 2 (Objets) de la série d'articles.
Vous pouvez le dire a
et en b
hériter Podcast
. Maintenant, que se passe-t-il si vous souhaitez ajouter une méthode à Podcast qui s'applique à tous après a
et qui b
a été instanciée? Dans ce cas, utilisez le .prototype
comme suit:
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
Maintenant, appelez encore a
et b
encore:
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
Vous pouvez trouver plus de détails sur les prototypes ici . Si vous voulez faire plus d'héritage, je vous suggère de vous pencher sur cela .
Les séries d'articles que j'ai mentionnées ci-dessus sont fortement recommandées à lire, elles incluent également les sujets suivants:
- Les fonctions
- Objets
- Prototypes
- Application de nouvelles fonctions aux constructeurs
- Levage
- Insertion automatique de point-virgule
- Propriétés et méthodes statiques
Notez que la "fonction" d' insertion automatique de point-virgule de JavaScript (comme mentionné dans 6.) est très souvent responsable de provoquer des problèmes étranges dans votre code. Par conséquent, je préfère le considérer comme un bug plutôt que comme une fonctionnalité.
Si vous souhaitez en savoir plus, voici un article MSDN assez intéressant sur ces sujets, certains d'entre eux décrits ici fournissent encore plus de détails.
Ce qui est également intéressant à lire (couvrant également les sujets mentionnés ci-dessus) sont les articles du guide JavaScript MDN :
Si vous voulez savoir comment émuler des out
paramètres c # (comme dans DateTime.TryParse(str, out result)
) en JavaScript, vous pouvez trouver un exemple de code ici.
Ceux d'entre vous qui travaillent avec IE (qui n'a pas de console pour JavaScript sauf si vous ouvrez les outils de développement à l'aide F12et ouvrez l'onglet console) peuvent trouver l'extrait de code suivant utile. Il vous permet d'utiliser console.log(msg);
comme utilisé dans les exemples ci-dessus. Insérez-le juste avant la Podcast
fonction.
Pour votre commodité, voici le code ci-dessus dans un extrait de code unique complet:
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>
Remarques:
Quelques bons conseils, astuces et recommandations sur la programmation JavaScript en général, vous pouvez les trouver ici (meilleures pratiques JavaScript) et là ('var' versus 'let') . Cet article est également recommandé sur les transtypages implicites (coercition) .
TypeScript est un moyen pratique d'utiliser des classes et de les compiler en JavaScript . Voici une aire de jeux où vous pouvez trouver des exemples vous montrant comment cela fonctionne. Même si vous n'utilisez pas TypeScript pour le moment, vous pouvez y jeter un œil, car vous pouvez comparer TypeScript avec le résultat JavaScript sur une vue côte à côte. La plupart des exemples sont simples, mais il existe également un exemple Raytracer que vous pouvez essayer instantanément. Je recommande particulièrement de regarder les exemples "Utilisation des classes", "Utilisation de l'héritage" et "Utilisation des génériques" en les sélectionnant dans la zone de liste déroulante - ce sont de beaux modèles que vous pouvez utiliser instantanément en JavaScript. Le tapuscrit est utilisé avec Angular.
Pour réaliser l' encapsulation des variables locales, des fonctions, etc. en JavaScript, je suggère d'utiliser un modèle comme le suivant (JQuery utilise la même technique):
<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>
Bien sûr, vous pouvez - et devez - mettre le code du script dans un *.js
fichier séparé ; c'est juste écrit en ligne pour garder l'exemple court.
Les fonctions auto-appelantes (également appelées IIFE = Immediateely Invoked Function Expression) sont décrites plus en détail ici .