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
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
|
---
title: Classes
slug: Web/JavaScript/Reference/Classes
tags:
- Classes
- Constructors
- ECMAScript 2015
- Inheritance
- Intermediate
- JavaScript
- TopicStub
translation_of: Web/JavaScript/Reference/Classes
---
<div>{{JsSidebar("Classes")}}</div>
<p>Klasy w Javascript zostały wprowadzone w ECMAScript 2015 jako lukier składniowy<strong> </strong>(ang. <em>syntactic sugar</em>) dla istniejącego, opartego na prototypach modelu dziedziczenia. Składnia klas <strong>nie</strong> wprowadza nowego zorientowanego obiektowo modelu dziedziczenia. Klasy wprowadzają znacznie prostszą i bardziej czytelną składnię do tworzenia obiektów i dziedziczenia.</p>
<h2 id="Definiowanie_klas">Definiowanie klas</h2>
<p>Klasy są w zasadzie "szczególnymi <a href="/pl/docs/Web/JavaScript/Reference/Functions">funkcjami</a>". Podobnie jak w funkcji można definiować <a href="/pl/docs/Web/JavaScript/Referencje/Operatory/Operator_function">wyrażenie <code>function</code></a> i <a href="/pl/docs/Web/JavaScript/Reference/Statements/function">deklaracje funkcji</a>, tak składnia klasy posiada dwa komponenty: <a href="/pl/docs/Web/JavaScript/Reference/Operators/class">wyrażenie <code>class</code></a> i <a href="/pl/docs/Web/JavaScript/Reference/Statements/class">deklaracje klasy</a>.</p>
<h3 id="Deklaracje_klas">Deklaracje klas</h3>
<p>Jednym ze sposobów definiowania klas jest <strong>deklaracja klasy</strong>. Aby zadeklarować klasę, należy użyć słowa kluczowego <code>class</code> wraz z nazwą klasy (w tym przypadku "Prostokat").</p>
<pre class="brush: js notranslate">class Prostokat {
constructor(wysokosc, szerokosc) {
this.wysokosc = wysokosc;
this.szerokosc = szerokosc;
}
}</pre>
<h4 id="Hoisting">Hoisting</h4>
<p>Ważną różnicą pomiędzy <strong>deklaracją funkcji</strong> a <strong>deklaracją klasy</strong> jest to, że deklaracje funkcji są przenoszone na początek ({{Glossary("Hoisting")}}) a klas nie. Najpierw musisz zadeklarować swoją klasę, by mieć do niej dostęp, w przeciwnym razie kod, jak ten poniżej, wygeneruje błąd {{jsxref("ReferenceError")}}:</p>
<pre class="brush: js example-bad notranslate">var p = new Prostokat(); // ReferenceError
class Prostokat {}
</pre>
<h3 id="Wyrażenie_class">Wyrażenie <code>class</code></h3>
<p><strong>Wyrażenie <code>class</code></strong> jest kolejnym sposobem definiowania klasy. Wyrażenia <code>class</code> mogą być nazwane lub nienazwane. Nazwa przypisana nazwanemu wyrażeniu <code>class</code> jest lokalna dla ciała klasy. (można ją odczytać z właściwości {{jsxref("Function.name", "name")}} klasy)</p>
<pre class="brush: js notranslate">// nienazwane
var Prostokat = class {
constructor(wysokosc, szerokosc) {
this.wysokosc = wysokosc;
this.szerokosc = szerokosc;
}
};
console.log(Prostokat.name); // Prostokat
// nazwane
var Prostokat = class Prostokat2 {
constructor(wysokosc, szerokosc) {
this.wysokosc = wysokosc;
this.szerokosc = szerokosc;
}
};
console.log(Prostokat.name); // Prostokat2
</pre>
<div class="note">
<p><strong>Uwaga</strong>: <strong>Wyrażenia </strong><code>class</code> dotykają te same kwestie związane z przenoszeniem na początek (ang. hoisting) co wspomnianych <strong>deklaracji </strong>klas.</p>
</div>
<h2 id="Ciało_klasy_i_definicje_metod">Ciało klasy i definicje metod</h2>
<p>Ciało klasy jest umieszczane w nawiasach klamrowych <code>{}</code>. To tam definiuje się metody, czy konstruktory.</p>
<h3 id="Tryb_ścisły">Tryb ścisły</h3>
<p>Ciało klasy jest wykonywane w <a href="/en-US/docs/Web/JavaScript/Reference/Strict_mode">trybie ścisłym</a> (ang. <em>strict mode</em>). W celu poprawienia wydajności, kod wykorzystywany tutaj podlega ścisłej składni; nie pozwala to na ukrycie niektórych wyjątków, a pewne słowa kluczowe są rezerwowane dla przyszłych wersji ECMAScript.</p>
<h3 id="Konstruktor">Konstruktor</h3>
<p><code><a href="/en-US/docs/Web/JavaScript/Reference/Classes/constructor">Constructor</a></code> jest szczególną metodą, która służy tworzeniu i inicjalizowaniu obiektu zdefiniowanego słowem kluczowym <code>class</code>. Dozwolony jest tylko jeden konstruktor w danej klasie. Jeśli klasa posiada więcej niż jedno wystąpienie metody <code>constructor</code>, wygenerowany zostanie błąd {{jsxref("SyntaxError")}}.</p>
<p>Aby wywołać konstruktor klasy bazowej, należy użyć słowa kluczowego <code>super</code>.</p>
<h3 id="Metody">Metody</h3>
<p>Zobacz też <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions">definiowanie metod</a>.</p>
<pre class="brush: js notranslate">class Prostokat {
constructor(wysokosc, szerokosc) {
this.wysokosc = wysokosc;
this.szerokosc = szerokosc;
}
// Getter
get pole() {
return this.liczPole();
}
// Method
liczPole() {
return this.wysokosc * this.szerokosc;
}
}
const kwadrat = new Prostokat(10, 10);
console.log(kwadrat.pole); // 100</pre>
<h3 id="Metody_i_właściwości_statyczne">Metody i właściwości statyczne</h3>
<p>Słowo kluczowe <code><a href="/en-US/docs/Web/JavaScript/Reference/Classes/static">static</a></code> definiuje metodę kub właściwość statyczną w klasie. Statyczne metody i właściwości są wywoływane bez <a href="/pl/docs/Learn/JavaScript/Obiekty" title='An example of class instance is "var john = new Person();"'>inicjalizowania</a> ich klas i <strong>nie mogą</strong> być wywołane przez instancję klasy.</p>
<pre class="brush: js notranslate">class Punkt {
constructor(x, y) {
this.x = x;
this.y = y;
}
static nazwa = "Punkt";
static odleglosc(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.sqrt(dx*dx + dy*dy);
}
}
const p1 = new Punkt(5, 5);
const p2 = new Punkt(10, 10);
p1.nazwa; // undefined
p1.odleglosc; // undefined
p2.nazwa; // undefined
p2.odleglosc; // undefined
console.log(Punkt.nazwa); // "Punkt"
console.log(Punkt.odleglosc(p1, p2)); // 7.0710678118654755</pre>
<h3 id="Powiązanie_this_z_metodami_niestatycznymi_i_statycznymi">Powiązanie <code>this</code> z metodami niestatycznymi i statycznymi</h3>
<p>Kiedy metoda typu <code>static</code> lub <code>prototype</code> jest wywoływana bez <code>this</code> (na przykład poprzez przypisanie metody do zmiennej), wtedy <code>this</code><em> </em>będzie <code>undefined</code> w środku metody. Takie zachowanie będzie takie same, nawet jeżeli dyrektywa <code>"use strict"</code> nie będzie obecna, ponieważ kod w obrębie metody danej klasy zawsze będzie wykonywał się jako <code>strict mode</code>.</p>
<pre class="brush: js notranslate">class Animal {
speak() {
return this;
}
static eat() {
return this;
}
}
let obj = new Animal();
obj.speak(); // obiekt Animal
let speak = obj.speak;
speak(); // undefined
Animal.eat(); // klasa Animal
let eat = Animal.eat;
eat(); // undefined</pre>
<p>Jeśli przepiszemy powyższy przykład z użyciem tradycyjnych funkcji bez dyrektywy <code>"use strict"</code>, to <code>this</code> wywołane w metodzie będzie automatycznie przypisane do pierwotnej wartości <code>this</code>, którą domyślnie jest <a href="/en-US/docs/Glossary/Global_object">global object</a>.</p>
<pre class="brush: js notranslate">function Animal() { }
Animal.prototype.speak = function() {
return this;
}
Animal.eat = function() {
return this;
}
let obj = new Animal();
let speak = obj.speak;
speak(); // global object
let eat = Animal.eat;
eat(); // global object
</pre>
<h3 id="Właściwości_instancji">Właściwości instancji</h3>
<p>Właściwości instancji muszą być zdefiniowane wewnątrz metody klasy:</p>
<pre class="brush: js notranslate">class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}</pre>
<p>Statyczne właściwości i właściwości prototypu muszą być zdefiniowane poza ciałem klasy:</p>
<pre class="brush: js notranslate">Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;</pre>
<h3 id="Deklaracje_pól">Deklaracje pól</h3>
<div class="blockIndicator warning">
<p>Publiczna i prywatne deklaracje pól są <a href="https://github.com/tc39/proposal-class-fields">funkcjonalnościami eksperymentalnymi</a> zaproponowanymi na <a href="https://tc39.es">TC39</a>. Wsparcie przeglądarek jest ograniczone, ale ta funkcjonalność może być używana przy użyciu systemów takich jak <a href="https://babeljs.io/">Babel</a>. </p>
</div>
<h4 id="Deklaracje_pól_publicznych">Deklaracje pól publicznych</h4>
<p>Przy użyciu deklaracji pól, powyższy przykład może być przepisany na:</p>
<pre class="brush: js notranslate">class Rectangle {
height = 0;
width;
constructor(height, width) {
this.height = height;
this.width = width;
}
}
</pre>
<p>Dzięki deklarowaniu pól na początku klasy, definicje klas stają się bardziej samodokumentujące, a pola są zawsze obecne.</p>
<p>Jak widać w powyższym przykładzie, pola mogą być zadeklarowane z lub bez domyślnej wartości.</p>
<p>Zobacz <a href="/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields">public class fields</a> po więcej informacji.</p>
<h4 id="Deklaracje_pól_prywatnych">Deklaracje pól prywatnych</h4>
<p>Używając deklaracji pól prywatnych, definicja może być zapisana w taki sposób:</p>
<pre class="brush: js notranslate">class Rectangle {
#height = 0;
#width;
constructor(height, width) {
this.#height = height;
this.#width = width;
}
}
</pre>
<p>Próba odniesienia się do prywatnego pola poza ciałem klasy wygeneruje błąd. Prywatne pola mogą być tylko odczytywane i modyfikowane wewnątrz ciała klasy. Poprzez definicję właściwości niewidocznych poza ciałem klasy, można zapewnić, że użytkownicy klasy nie będą polegali na jej wewnętrznych właściwościach.</p>
<div class="note">
<p>Pola prywatne mogą być tylko zadeklarowane na początku ciała klasy</p>
</div>
<p>Prywatnych pól nie da się utworzyć później, poprzez przypisywanie, tak jak normalnych właściwości.</p>
<p>Po więcej informacji zobacz <a href="/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields">private class fields</a>.</p>
<h2 id="Podklasy_z_extends">Podklasy z <code>extends</code></h2>
<p>Słowo kluczowe <code><a href="/en-US/docs/Web/JavaScript/Reference/Classes/extends">extends</a></code> jest używane w <em>deklaracjach klas</em> lub <em>wyrażeniach klas</em> do tworzenia klasy jako elementu potomnego innej klasy.</p>
<pre class="brush: js notranslate">class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
constructor(name) {
super(name); // wywyłanie konstruktora klasy nadrzędnej poprzez użycie super()
}
speak() {
console.log(this.name + ' barks.');
}
}
let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
</pre>
<p>Jeśli w podklasie znajduje się konstruktor, musi najpierw wywołać super() przed użyciem "this".</p>
<p>Można również rozszerzyć tradycyjne klasy oparte na funkcjach:</p>
<pre class="brush: js notranslate">function Animal (name) {
this.name = name;
}
Animal.prototype.speak = function () {
console.log(this.name + ' makes a noise.');
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}
let d = new Dog('Mitzie');
d.speak(); // Mitzie barks
</pre>
<p>Zwróć uwagę, że klasy nie mogą rozszerzać zwykłych (niezdatnych do konstrukcji) obiektów. Jeśli chcesz dziedziczyć po zwykłym obiekcie, możesz, zamiast tego użyć {{jsxref ("Object.setPrototypeOf()")}}:</p>
<pre class="brush: js notranslate">var Animal = {
speak() {
console.log(this.name + ' makes a noise.');
}
};
class Dog {
constructor(name) {
this.name = name;
}
}
Object.setPrototypeOf(Dog.prototype, Animal);// If you do not do this you will get a TypeError when you invoke speak
let d = new Dog('Mitzie');
d.speak(); //Mitzie makes a noise.
</pre>
<h2 id="Species">Species</h2>
<p>Jeśli chcesz zwrócić obiekt {{jsxref("Array")}} w twojej klasie <code>MyArray</code>, która dziedziczy po <code>Array</code>, to możesz użyć wzorca "species", który pozwala na nadpisywanie domyślnych konstruktorów.</p>
<p>Na przykład, wywołanie metody {{jsxref("Array.map", "map()")}} zwraca domyślny konstruktor <code>MyArray</code>. Użycie {{jsxref("Symbol.species")}} pozwala na nadpisanie tego zachowania tak, by zwracany był obiekt typu <code>Array</code>, a nie <code>MyArray</code>:</p>
<pre class="brush: js notranslate">class MyArray extends Array {
// Nadpisanie domyślnego kontruktora
static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
</pre>
<h2 id="Słowo_kluczowe_super">Słowo kluczowe <code>super</code></h2>
<p>Słowo kluczowe <strong>super </strong>jest wykorzystywane do udostępniania i korzystania z funkcji klasy, po której nasz obiekt dziedziczy.</p>
<pre class="brush: js notranslate">class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(`${this.name} roars.`);
}
}
let l = new Lion('Fuzzy');
l.speak();
// Fuzzy makes a noise.
// Fuzzy roars.</pre>
<h2 id="Mix-ins">Mix-ins</h2>
<p>Abstrakcyjne podklasy lub <em>mix-ins</em> są szablonami dla klas. Klasa może mieć tylko jedną klasę nadrzędną, więc dziedziczenie z wielu klas jest niemożliwe. Cała funkcjonalność musi być dostarczona przez jedną klasę nadrzędną.</p>
<p>Funkcja przyjmująca klasę nadrzędną jako argument i zwracająca podklasę rozszerzającą klasę nadrzędną może być użyta do implementacji mix-in'ów:</p>
<pre class="brush: js notranslate">var calculatorMixin = Base => class extends Base {
calc() { }
};
var randomizerMixin = Base => class extends Base {
randomize() { }
};
</pre>
<p>Klasa używająca tych mix-in'ów może być zapisana w taki sposób:</p>
<pre class="brush: js notranslate">class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }</pre>
<h2 id="Specyfikacje">Specyfikacje</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Specyfikacja</th>
<th scope="col">Status</th>
<th scope="col">Komentarz</th>
</tr>
<tr>
<td>{{SpecName('ES2015', '#sec-class-definitions', 'Class definitions')}}</td>
<td>{{Spec2('ES2015')}}</td>
<td>Initial definition.</td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-class-definitions', 'Class definitions')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="Kompatybilność">Kompatybilność</h2>
<p>{{Compat("javascript.classes")}}</p>
<h2 id="Zobacz_też">Zobacz też</h2>
<ul>
<li><a href="/en-US/docs/Web/JavaScript/Reference/Functions">Functions</a></li>
<li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/class"><code>class</code> declaration</a></li>
<li><a href="/en-US/docs/Web/JavaScript/Reference/Operators/class"><code>class</code> expression</a></li>
<li>{{jsxref("Operators/super", "super")}}</li>
<li><a href="https://hacks.mozilla.org/2015/07/es6-in-depth-classes/">Blog post: "ES6 In Depth: Classes"</a></li>
</ul>
|