1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
---
title: Champs de classe publics
slug: Web/JavaScript/Reference/Classes/Class_fields
tags:
- Classes
- Fonctionnalité du langage
- JavaScript
translation_of: Web/JavaScript/Reference/Classes/Public_class_fields
---
<div>{{JsSidebar("Classes")}}{{SeeCompatTable}}</div>
<div class="note">
<p><strong>Cette page décrit des fonctionnalités expérimentales.</strong></p>
<p>Les déclarations de champs, tant publics que privés, sont <a href="https://github.com/tc39/proposal-class-fields">une fonctionnalité expérimentale (étape 3)</a> proposée au <a href="https://tc39.github.io/beta/">TC39</a>, le comité des standards JavaScript.</p>
<p>La prise en charge dans les navigateurs est limitée, mais cette fonctionnalité peut être utilisée à travers une étape de contruction avec des systèmes tels que <a href="https://babeljs.io/">Babel</a>. Voir <a href="https://wiki.developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Classes/Class_fields$edit#Browser_compatibility">l'information de compatibilité</a> ci-dessous.</p>
</div>
<p>Les champs publics, tant statiques que d'instance, sont des propriétés qui peuvent être écrites, et qui sont énumérables et configurables. En tant que telles, à la différence de leurs contreparties privées, elles participent à l'héritage du prototype.</p>
<h2 id="Syntaxe">Syntaxe</h2>
<pre class="syntaxbox notranslate">class ClasseAvecChampDInstance {
champDInstance = 'champ d\'instance'
}
class ClasseAvecChampStatique {
static champStatique = 'champ statique'
}
class ClasseAvecMethodeDInstancePublique {
methodePublique() {
return 'hello world'
}
}
</pre>
<h2 id="Exemples">Exemples</h2>
<h3 id="Champs_statiques_publics">Champs statiques publics</h3>
<p>Les champs statiques publics sont utiles lorsque vous voulez qu'un champ n'existe qu'une seule fois par classe, pas dans chaque instance que vous créez. Cela est utile pour des caches, une configuration fixe, ou tout autres données dont vous n'avez pas besoin qu'elles soient répliquées à travers les instances.</p>
<p>Les champs statiques publics sont déclarés en utilisant le mot-clé <code>static</code>. Ils sont ajoutés au constructeur de la classe au moment de l'évaluation de la classe en utilisant {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}}. On y accède à nouveau à partir du constructeur de la classe.</p>
<pre class="brush: js notranslate">class ClasseAvecChampStatique {
static champStatique = 'champ statique'
}
console.log(ClasseAvecChampStatique.champStatique)
// affichage attendu : "champ statique"
</pre>
<p>Les champs sans initialiseur sont initialisés à <code>undefined</code>.</p>
<pre class="brush: js notranslate">class ClasseAvecChampStatique {
static champStatique
}
console.assert(ClasseAvecChampStatique.hasOwnProperty('champStatique'))
console.log(ClasseAvecChampStatique.champStatique)
// affichage attendu : "undefined"</pre>
<p>Les champs statiques publics ne sont pas réinitialisés dans les sous-classes, mais on peut y accéder via la chaîne de prototypes.</p>
<pre class="brush: js notranslate">class ClasseAvecChampStatique {
static champStatiqueDeBase = 'champ de base'
}
class SousClasseAvecChampStatique extends ClasseAvecChampStatique {
static sousChampStatique = 'champ de la sous-classe'
}
console.log(SousClasseAvecChampStatique.sousChampStatique)
// affichage attendu : "champ de la sous-classe"
console.log(SousClasseAvecChampStatique.champStatiqueDeBase)
// affichage attendu : "champ de base"</pre>
<p>Lors de l'initialisation des champs, <code>this</code> fait référence au constructeur de la classe. Vous pouvez aussi le référencer par son nom, et utiliser <code>super</code> pour obtenir le constructeur de la superclasse (s'il en existe un) :</p>
<pre class="brush: js notranslate">class ClasseAvecChampStatique {
static champStatiqueDeBase = 'champ statique de base'
static autreChampStatiqueDeBase = this.champStatiqueDeBase
static methodeStatiqueDeBase() { return 'affichage de la méthode statique de base' }
}
class SousClasseAvecChampStatique extends ClasseAvecChampStatique {
static sousChampStatique = super.methodeStatiqueDeBase()
}
console.log(ClasseAvecChampStatique.autreChampStatiqueDeBase)
// affichage attendu : "champ statique de base"
console.log(SousClasseAvecChampStatique.sousChampStatique)
// affichage attendu : "affichage de la méthode statique de base"
</pre>
<h3 id="Champs_dinstance_publics">Champs d'instance publics</h3>
<p>Les champs d'instance publics existent dans chaque instance créée d'une classe. En déclarant un champ public, vous pouvez vous assurer que le champ est toujours présent, et que la définition de la classe est davantage auto-documentée.</p>
<p>Les champs d'instance publics sont ajoutés grâce à {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}}, soit au moment de la construction dans la classe de base (avant que le corps du constructeur ne soit exécuté), soit juste après le retour de <code>super()</code> dans une sous-classe.</p>
<pre class="brush: js notranslate">class ClasseAvecChampDInstance {
champDInstance = 'champ d\'instance'
}
const instance = new ClasseAvecChampDInstance()
console.log(instance.champDInstance)
// affichage attendu : "champ d'instance"</pre>
<p>Les champs sans initialiseur sont initialisés à <code>undefined</code>.</p>
<pre class="brush: js notranslate">class ClasseAvecChampDInstance {
champdDInstance
}
const instance = new ClasseAvecChampDInstance()
console.assert(instance.hasOwnProperty('champDInstance'))
console.log(instance.champDInstance);
// affichage attendu : "undefined"</pre>
<p>À l'instar des propriétés, les noms de champ peuvent être calculés :</p>
<pre class="brush: js notranslate">const PREFIXE = 'prefixe';
class ClasseAvecNomDeChampCalcule {
[`${PREFIXE}Champ`] = 'champ préfixé'
}
const instance = new ClasseAvecNomDeChampCalcule()
console.log(instance.prefixeChamp)
// affichage attendu : "champ préfixé"</pre>
<p>Lors de l'initialisation des champs, <code>this</code> fait référence à l'instance en cours de construction. Tout comme dans les méthodes d'instance publiques, si vous êtes dans une sous-classe, vous pouvez accéder au prototype de la superclasse en utilisant <code>super</code>.</p>
<pre class="brush: js notranslate">class ClasseAvecChampDInstance {
champDInstanceDeBase = 'champ de base'
autreChampDInstanceDeBase = this.champDInstanceDeBase
methodeDInstanceDeBase() { return 'affichage de la méthode de base' }
}
class SousClasseAvecChampDInstance extends ClasseAvecChampDInstance {
sousChampDInstance = super.methodeDInstanceDeBase()
}
const base = new ClasseAvecChampDInstance()
const sous = new SousClasseAvecChampDInstance()
console.log(base.autreChampDInstanceDeBase)
// affichage attendu : "champ de base"
console.log(sous.sousChampDInstance)
// affichage attendu : "affichage de la méthode de base"</pre>
<h3 id="Méthodes_publiques">Méthodes publiques</h3>
<h4 id="Méthodes_statiques_publiques">Méthodes statiques publiques</h4>
<p>Le mot-clé <code><strong>static</strong></code> définit une méthode statique pour une classe. Les méthodes statiques ne sont pas appelées dans les instances de la classe. A la place, elles le sont dans la classe elle-même. Ce sont souvent des méthodes utilitaires, comme des fonctions pour créer ou cloner des objets.</p>
<pre class="brush: js notranslate">class ClasseAvecMethodeStatique {
static methodeStatique() {
return 'la méthode statique a été appelée.';
}
}
console.log(ClasseAvecMethodeStatique.methodeStatique());
// affichage attendu : "la méthode statique a été appelée."</pre>
<p>Les méthodes statiques sont ajoutées au constructeur de la classe grâce à {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}} au moment de l'évaluation de la classe. Ces méthodes peuvent être écrites, ne sont pas énumérables et sont configurables.</p>
<h4 id="Méthodes_dinstance_publiques">Méthodes d'instance publiques</h4>
<p>Comme leur nom l'implique, les méthodes d'instance publiques sont des fonctions disponibles dans les instances de la classe.</p>
<pre class="brush: js notranslate">class ClasseAvecMethodeDInstancePublique {
methodePublique() {
return 'hello world'
}
}
const instance = new ClasseAvecMethodeDInstancePublique()
console.log(instance.methodePublique())
// affichage attendu : "hello world"</pre>
<p>Les méthodes d'instance publiques sont ajoutées au prototype au moment de l'évaluation de la classe en utilisant {{jsxref("Global_Objects/Object/defineProperty", "Object.defineProperty()")}}. Elles peuvent être écrites, ne sont pas énumérables et sont configurables.</p>
<p>Vous pouvez utiliser des fonctions génératrices, asynchrones et génératrices asynchrones.</p>
<pre class="brush: js notranslate">class ClasseAvecMethodesFantaisie {
*methodeGeneratrice() { }
async methodeAsynchrone() { }
async *methodeGeneratriceAsynchrone() { }
}</pre>
<p>A l'intérieur des méthodes d'instance, <code>this</code> fait référence à l'instance elle-même. Dans les sous-classes, <code>super</code> vous donne accès au prototype de la superclasse, ce qui vous permet d'appeler les méthodes de la superclasse.</p>
<pre class="brush: js notranslate">class ClasseDeBase {
msg = 'hello world'
methodePubliqueDeBase() {
return this.msg
}
}
class SousClasse extends ClasseDeBase {
sousMethodePublique() {
return super.methodePubliqueDeBase()
}
}
const instance = new SousClasse()
console.log(instance.sousMethodePublique())
// affichage attendu : "hello world"
</pre>
<p>Les accesseurs et les mutateurs sont des méthodes spéciales qui sont liées à une propriété de classe, et sont appelées lorsqu'on accède à cette propriété ou qu'on la définit. Utilisez la syntaxe <a href="https://developer.mozilla.org/fr-FR/docs/Web/JavaScript/Reference/Functions/get">get</a> et <a href="https://developer.mozilla.org/fr-FR/docs/Web/JavaScript/Reference/Functions/set">set</a> pour déclarer un accesseur ou un mutateur publique d'une instance.</p>
<pre class="brush: js notranslate">class ClasseAvecGetSet {
#msg = 'hello world'
get msg() {
return this.#msg
}
set msg(x) {
this.#msg = `hello ${x}`
}
}
const instance = new ClasseAvecGetSet();
console.log(instance.msg);
// affichage attendu : "hello world"
instance.msg = 'gâteau';
console.log(instance.msg);
// affichage attendu : "hello gâteau"
</pre>
<h2 id="Spécifications">Spécifications</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Spécification</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('Public and private instance fields', '#prod-FieldDefinition', 'FieldDefinition')}}</td>
</tr>
</tbody>
</table>
<h2 id="Compatibilité_des_navigateurs">Compatibilité des navigateurs</h2>
<div class="hidden">Le tableau de compatibilité de cette page a été généré à partir de données structurées. Si vous souhaitez contribuer à ces données, n'hésitez pas à consulter <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> et à nous envoyer une <em>pull request</em>.</div>
<p>{{Compat("javascript.classes.public_class_fields")}}</p>
<h2 id="Voir_aussi">Voir aussi</h2>
<ul>
<li><a href="https://rfrn.org/~shu/2018/05/02/the-semantics-of-all-js-class-elements.html">The Semantics of All JS Class Elements</a></li>
</ul>
|