aboutsummaryrefslogtreecommitdiff
path: root/files/pl/conflicting/learn/javascript/objects/index.html
blob: cb264148140dc2b6973026139b1ba5f499d2c44c (plain)
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
---
title: Wprowadzenie do programowania obiektowego w języku JavaScript
slug: Web/JavaScript/Wprowadzenie_do_programowania_obiektowego_w_jezyku_JavaScript
translation_of: Learn/JavaScript/Objects
translation_of_original: Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
---
<p>JavaScript jest zorientowany obiektowo do szpiku kości dzięki potężnym, elastycznym możliwościom realizacji OOP. <span style="line-height: 1.5;">Ten artykuł zawiera wprowadzenie do programowania obiektowego (ogółem), analizuje model obiektowy w JavaScript i w końcu demonstruje aspekty programowania obiektowego w JavaScript.</span></p>

<h2 id="JavaScript_Review" name="JavaScript_Review">Przegląd JavaScript</h2>

<p>Jeśli nie czujesz się pewnie w zagadnieniach dotyczących JavaScript takich, jak zmienne, typy, funkcje oraz zasięg, możesz przeczytać o nich w <a href="/en/JavaScript/A_re-introduction_to_JavaScript" title="en/JavaScript/A_re-introduction_to_JavaScript">Ponownym wprowadzeniu do JavaScript (angielski)</a>. Możesz także zasięgnąć wiedzy zawartej w <a href="/en/JavaScript/Guide" title="en/JavaScript/Guide">Core JavaScript 1.5 Guide</a>.</p>

<h2 id="Object-oriented_programming" name="Object-oriented_programming">Programowanie zorientowane obiektowo</h2>

<p>Programowanie zorientowane obiektowo jest paradygmatem programowania, który korzysta z abstrakcji do tworzenia modeli opartych na świecie rzeczywistym. Stosuje on kilka technik z poprzednio ustanowionych paradygmatów, np. modułowość, polimorfizm czy enkapsulację. Obecnie wiele popularnych języków programowania (takich, jak Java, JavaScript, C#, C++, Python, PHP, Ruby i Objective-C) wspierają programowanie zorientowane obiektowo (OOP - z ang. "object-oriented programming").</p>

<p>Programowanie zorientowane obiektowo może być rozumiane jako sposób projektowania oprogramowania stosujący kolekcję powiązanych ze sobą obiektów, w przeciwieństwie do tradycyjnego punktu widzenia, gdzie program może być rozumiany jako zestaw funkcji lub, po prostu, jako lista instrukcji przekazywanych do komputera. W OOP każdy obiekt jest zdolny odbierać wiadomości, przetwarzać dane i wysyłać wiadomości do innych obiektów. Każdy obiekt może być rozumiany jako niezależna mała maszyna pełniąca odrębną rolę lub odpowiedzialność.</p>

<p><span style="line-height: 1.5;">Programowanie obiektowe ma na celu promować większą elastyczność i łatwość rozwoju w programowaniu. Jest ono bardzo popularne przy tworzeniu oprogramowania na dużą skalę. Dzięki silnemu naciskowi na modułowość, kod programu zorientowany obiektowo jest łatwiejszy do napisania i późniejszego zrozumienia, stając się łatwiejszym do bezpośredniej analizy, kodowania i rozumienia złożonych sytuacji i procedur niż mniej modułowe metody programowania.</span><sup><a href="#References">2</a></sup></p>

<h2 id="Terminology" name="Terminology">Terminologia</h2>

<dl>
 <dt>Przestrzeń nazw (ang. "namespace")</dt>
 <dd>Przestrzeń pozwalająca programiście na zawarcie wszystkich funkcjonalności pod unikalną nazwą, właściwą dla danej aplikacji.</dd>
 <dt>Klasa (ang. "class")</dt>
 <dd>Definiuje własności obiektu.</dd>
 <dt>Obiekt (ang. "object")</dt>
 <dd>Instancja (byt, twór) klasy.</dd>
 <dt>Właściwość (ang. "property")</dt>
 <dd>Własność obiektu, np. kolor.</dd>
 <dt>Metoda (ang. "method")</dt>
 <dd>Zdolność (czynność) obiektu, np. chodzenie (idź).</dd>
 <dt>Konstruktor (ang. "constructor")</dt>
 <dd>Metoda wywoływana w momencie inicjalizacji obiektu.</dd>
 <dt>Dziedziczenie (ang. "inheritance")</dt>
 <dd>Klasa może dziedziczyć własności od innej klasy.</dd>
 <dt>Hermetyzacja (lub enkapsulacja - ang. "encapsulation")</dt>
 <dd>Klasa definiuje tylko własności obiektu, podczas gdy metoda definiuje tylko sposób realizacji.</dd>
 <dt>Abstrakcja (ang. "abstraction")</dt>
 <dd>Koniunkcja złożonego dziedziczenia, metod, właściwości obiektu musi dobrze oddawać model rzeczywistości.</dd>
 <dt>Polimorfizm (ang. "polymorphism")</dt>
 <dd><em>Poli </em>znaczy "wiele", a <em>morfizm</em> oznacza "formy". Różne klasy mogą definiować takie same metody albo właściwości.</dd>
</dl>

<p>Bardziej obszerną definicję programowania obiektowego można znaleźć w <a href="http://pl.wikipedia.org/wiki/Programowanie_obiektowe">Programowaniu obiektowym</a> na Wikipedii.</p>

<h2 id="Programowanie_oparte_na_prototypie">Programowanie oparte na prototypie</h2>

<p>Programowanie prototypowe jest stylem programowania obiektowego, w którym klasy nie są obecne, a ponowne wykorzystanie zachowań (w językach opartych na klasach znane jako dziedziczenie) jest realizowane przez proces dekoracji istniejących obiektów, które służą jako prototypy. Ten model jest znany również jako programowanie "bezklasowe", "zorientowane prototypowo" lub "oparte na instancji".</p>

<p>Oryginalnym (i najbardziej kanonicznym) przykładem języka opartego na prototypie jest język programowaina Self stworzony przez Davida Ungara i Randalla Smitha. Niemniej jednak, programowanie w stylu bezklasowym stało się ostatnimi czasy bardzo popularne i zostało zaimplementowane w takich językach, jak Javascript, Cecil, NewtonScript, Io, MOO, REBOL, Kevo, Squeak (podczas używania frameworka Viewer do manipulacji komponentami Morphic) i kilku innych.<sup><a href="#Reference">2</a></sup></p>

<h2 id="JavaScript_Object_Oriented_Programming" name="JavaScript_Object_Oriented_Programming">OOP w języku JavaScript</h2>

<h3 id="Przestrzeń_nazw">Przestrzeń nazw</h3>

<p>Przestrzeń nazw jest pojemnikiem pozwalającym programiście na zawarcie wszystkich funkcjonalności pod unikalną nazwą, właściwą dla danej aplikacji. W JavaScript przestrzeń nazw jest po prostu obiektem przechowującym metody, właściwości i inne obiekty. Cel przyświecający przestrzeniom nazw w JavaScript jest prosty: utworzony zostaje jeden globalny obiekt, a wszystkie zmienne, metody i funkcje stają się właściwościami tego obiektu. Użycie przestrzeni nazw zmniejsza również ryzyko kolizji nazw w aplikacji.</p>

<p>Obiekt jest przestrzenią nazw:<br>
 <br>
 Stwórzmy globalny obiekt o nazwie MYAPP</p>

<pre class="brush: js">// globalna przestrzeń nazw
var MYAPP = MYAPP || {};</pre>

<p><span style="background-color: #ffffff; color: #4d4e53; font-style: normal; line-height: 1.5;">W powyższym przykładzie najpierw sprawdzamy czy MYAPP jest już zdefiniowany w tym samym lub innym pliku. Jeśli tak, używamy istniejącego globalnego obiektu MYAPP. W przeciwnym razie tworzymy pusty obiekt MYAPP, który zenkapsuluje metody, funkcje, zmienne i obiekty.</span></p>

<p>Możemy również utworzyć podrzędną przestrzeń nazw:</p>

<pre class="brush: js">// pod-przestrzeń nazw
MYAPP.event = {};</pre>

<p>Poniżej znajduje się kod tworzący przestrzeń nazw i dodający zmienne, funkcje i metody:</p>

<pre class="brush: js">// Utwórz pojemnik MYAPP.commonMethod na typowe metody i właściwości
MYAPP.commonMethod = {
  regExForName: "", // zdefiniuj wyrażenie regularne do walidacji nazwiska
  regExForPhone: "", // <span style="font-size: 1rem;">zdefiniuj wyrażenie regularne do walidacji numeru telefonu</span>
  validateName: function(name){
    // Zrób coś z nazwiskiem. Możesz użyć zmiennej regExForName
    // użycie "this.regExForName"
  },

  validatePhoneNo: function(phoneNo){
    // zrób coś z numerem telefonu
  }
}

// Obiekt razem z deklaracją metod
MYAPP.event = {
    addListener: function(el, type, fn) {
    // jakiś kod
    },
   removeListener: function(el, type, fn) {
    // jakiś kod
   },
   getEvent: function(e) {
   // jakiś kod
   }

   // Można dodać kolejne metody i właściwości
}

// Składnia do użycia metody AddListener:
MYAPP.event.addListener("yourel", "type", callback);</pre>

<h3 id="Core_Objects" name="Core_Objects">Obiekty wbudowane</h3>

<p>JavaScript posiada kilka obiektów wbudowanych, na przykład Math, Object, Array, i String. Poniższy przykład pokazuje, jak użyć obiektu Math do pobrania pseudo-losowej liczby używając metody <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">random()</span><span style="line-height: 1.5;">.</span></p>

<pre class="brush: js">alert(Math.random());
</pre>

<div class="note"><strong>Notka:</strong> Ten i wszystkie dalsze przykłady zakładają, że istnieje funkcja globalna <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">alert</span><span style="line-height: 1.5;"> (taka, jak ta zaimplementowana w przeglądarkach internetowych). Tak naprawdę funkcja </span><span style="font-family: 'Courier New','Andale Mono',monospace;">alert</span><span style="line-height: 1.5;"> nie jest częścią języka JavaScript.</span></div>

<p>Artykuł <a href="/En/Core_JavaScript_1.5_Reference/Global_Objects" title="En/Core_JavaScript_1.5_Reference/Global_Objects">Core JavaScript 1.5 Reference:Global Objects</a> zawiera listę wszystkich obiektów wbudowanych w JavaScript.</p>

<p>Każdy obiekt w JavaScript jest instancją obiektu <span style="font-family: 'Courier New','Andale Mono',monospace;">Object</span> i tym samym dziedziczy jego wszystkie właściwości i metody.</p>

<h3 id="Custom_Objects" name="Custom_Objects">Własne obiekty</h3>

<h4 id="The_Class" name="The_Class">Klasa</h4>

<p>JavaScript jest językiem opartym na prototypie, w którym nie występuje pojęcie klasy, w przeciwieństwie do języków takich, jak C++ czy Java. Fakt ten bywa dezorientujący dla programistów przyzwyczajonych do języków z pojęciem klasy. Zamiast klas, JavaScript stosuje funkcje. Zdefiniowanie klasy ogranicza się do prostej czynności, jaką jest zdefiniowanie funkcji. W poniższym przykładzie definiujemy nową klasę Person.</p>

<pre class="brush: js">function Person() { }
or
var Person = function(){ }
</pre>

<h4 id="The_Object_.28Class_Instance.29" name="The_Object_.28Class_Instance.29">Obiekt (instancja klasy)</h4>

<p>Żeby utworzyć nową instancję obiektu <em>obj</em>, używamy wyrażenia <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">new </span><em>obj</em><span style="line-height: 1.5;">, przypisując jego wynik (który jest typu </span><em>obj</em><span style="line-height: 1.5;">) do zmiennej, żeby później mieć do niego dostęp.</span></p>

<p>W poniższym przykładzie definiujemy klasę Person i tworzymy dwie instancje (person1 i person2).</p>

<pre class="brush: js">function Person() { }
var person1 = new Person();
var person2 = new Person();
</pre>

<div class="note">Zobacz również <a href="/en/JavaScript/Reference/Global_Objects/Object/create" title="Object.create">Object.create</a>, który jest nową metodą instancjalizacji.</div>

<h4 id="The_Constructor" name="The_Constructor">Konstruktor</h4>

<p>Konstruktor jest wywoływany w momencie instancjalizacji (moment, w którym instancja obiektu zostaje utworzona). Konstruktor jest metodą klasy. W JavaScript, funkcja służy za konstruktor obiektu. Nie ma jednak wyraźnej potrzeby definiowania konstruktora. Każda akcja zadeklarowana w konstruktorze zostanie wykonana w momencie utworzenia obiektu.</p>

<p>Konstruktor jest używany do ustawienia właściwości obiektu lub do wywołania metod przygotowujących obiekt do użytku.</p>

<p>W poniższym przykładzie konstruktor klasy Person wyświetla ostrzeżenie w momencie kiedy Person zostaje utworzony.</p>

<pre class="brush: js">function Person() {
  alert('Person został utworzony');
}

var person1 = new Person();
var person2 = new Person();
</pre>

<h4 id="The_Property_.28object_attribute.29" name="The_Property_.28object_attribute.29">Właściwość (atrybut obiektu)</h4>

<p>Właściwości są zmiennymi zawartymi wewnątrz klasy. Każda instancja obiektu posiada te właściwości. Właściwości powinny być ustawiane we właściwości prototype klasy (funkcji), dzięki czemu dziedziczenie zadziała prawidłowo.</p>

<p>Dostęp do właściwości z wnętrza klasy odbywa się za pomocą słowa kluczowego <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">this</span><span style="line-height: 1.5;">, które odnosi się do aktualnego obiektu. Dostęp (odczyt lub zapis) do właściwości poza klasą odbywa się za pomocą składni: NazwaInstancji.Wlasciwosc; jest to taka sama składnia, jak w językach C++, Java i szeregu innych języków.</span></p>

<p>W poniższym przykładzie definiujemy właściwość <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">firstName</span><span style="line-height: 1.5;"> dla klasy </span><span style="font-family: 'Courier New','Andale Mono',monospace;">Person</span><span style="line-height: 1.5;"> i robimy to w momencie utworzenia obiektu.</span></p>

<pre class="brush: js">function Person(firstName) {
  this.firstName = firstName;
  alert('Person instantiated');
}

var person1 = new Person('Alice');
var person2 = new Person('Bob');

// Pokaż właściwości firstName obiektów
alert('person1 nazywa się ' + person1.firstName); // komunikat "person1 nazywa się Alice"
alert('person2 nazywa się ' + person2.firstName); // komunikat "person2 nazywa się Bob"
</pre>

<h4 id="The_methods" name="The_methods">Metody</h4>

<p>Metody opierają się na tej samej logice, co właściwości; różnica polega na tym, że są one funkcjami i definiuje się je jak funkcje. Wywołanie metody wygląda podobnie do wywołania właściwości, z tym, że dodajemy ( ) na końcu nazwy metody, czasami z argumentami. Żeby zdefiniować metodę, przypisujemy funkcję do jakiejś właściwości obiektu <span style="font-family: 'Courier New','Andale Mono',monospace;">prototype</span> klasy; nazwa właściwości staje się nazwą metody, po jakiej wywołamy ją na obiekcie.</p>

<p>W poniższym przykładzie definiujemy i używamy metodę <span style="font-family: 'Courier New','Andale Mono',monospace;">sayHello()</span> dla klasy Person.</p>

<pre class="brush: js">function Person(firstName) {
  this.firstName = firstName;
}

Person.prototype.sayHello = function() {
  alert("Hello, I'm " + this.firstName);
};

var person1 = new Person("Alice");
var person2 = new Person("Bob");

// wywołanie metody sayHello klasy Person
person1.sayHello(); // komunikat "Hello, I'm Alice"
person2.sayHello(); // komunikat "Hello, I'm Bob"
</pre>

<p>W JavaScript metody to zwykłe funkcje, które są przypisane do obiektu jako jego właściwości, dzięki czemu mogą być wywoływane w jego kontekście. Przyjrzyj się natępującemu przykładowi kodu:</p>

<pre class="brush: js">function Person(firstName) {
  this.firstName = firstName;
}

Person.prototype.sayHello = function() {
  alert("Hello, I'm " + this.firstName);
};

var person1 = new Person("Alice");
var person2 = new Person("Bob");
var helloFunction = person1.sayHello;

person1.sayHello();                                 // komunikat "Hello, I'm Alice"
person2.sayHello();                                 // <span style="font-size: 1rem;">komunikat</span><span style="font-size: 1rem;"> "Hello, I'm Bob"</span>
helloFunction();                                    // <span style="font-size: 1rem;">komunikat</span><span style="font-size: 1rem;"> "Hello, I'm undefined" (lub niepowodzenie</span>
                                                    // wyświetlające TypeError w trybie strict)
alert(helloFunction === person1.sayHello);          // <span style="font-size: 1rem;">komunikat</span><span style="font-size: 1rem;"> true</span>
alert(helloFunction === Person.prototype.sayHello); // <span style="font-size: 1rem;">komunikat</span><span style="font-size: 1rem;"> true</span>
helloFunction.call(person1);                        // <span style="font-size: 1rem;">komunikat</span><span style="font-size: 1rem;"> "Hello, I'm Alice"</span>
</pre>

<p>Jak pokazuje powyższy przykład, wszystkie odniesienia do funkcji <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">sayHello </span><span style="line-height: 1.5;"></span><span style="line-height: 1.5;"> to w obiekcie person1, w </span><code style="font-style: normal; line-height: 1.5;">Person.prototype</code><span style="line-height: 1.5;">, w </span><code style="font-style: normal; line-height: 1.5;">helloFunction</code><span style="line-height: 1.5;">variable, itd. — dotyczą tej <em>samej funkcji</em>. W trakcie wywołania funkcji, wartość </span><span style="font-family: 'Courier New','Andale Mono',monospace;">this</span><span style="line-height: 1.5;"> zależy od tego, jak ją wywołamy. W typowym przypadku, gdzie wywołujemy funkcję jako metodę obiektu </span><span style="line-height: 1.5;">— </span><code style="font-style: normal; line-height: 1.5;">person1.sayHello()</code><span style="line-height: 1.5;"> — </span><code style="font-style: normal; line-height: 1.5;">this</code><span style="line-height: 1.5;"> odnosi się do obiektu, z którego funkcja pochodzi (person1), stąd </span><span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">person1.sayHello()</span><span style="line-height: 1.5;"> używa nazwy "Alice", a </span><span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">person2.sayHello() </span><span style="line-height: 1.5;">używa nazwy "Bob". Natomiast wywołanie funkcji ze zmiennej </span><span style="line-height: 1.5;">— </span><code style="font-style: normal; line-height: 1.5;">helloFunction()</code><span style="line-height: 1.5;"> —</span><span style="line-height: 1.5;"> ustawia </span><span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">this</span><span style="line-height: 1.5;"> na obiekt globalny (</span><span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">window</span><span style="line-height: 1.5;"> w przypadku przeglądarek). Ponieważ ten obiekt najprawdopodobniej nie posiada właściwości </span><span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">firstName</span><span style="line-height: 1.5;">, ostatecznie otrzymujemy komunikat "Hello, I'm undefined". (Tak będzie w trybie loose; byłoby inaczej [błąd] w <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode">trybie strict</a>, ale nie będziemy go tutaj opisywać, żeby nie wprowadzać zamieszania). Możemy też ustawić </span><span style="font-family: 'Courier New','Andale Mono',monospace;">this</span><span style="line-height: 1.5;"> wedle uznania, używając funkcji </span><span style="font-family: 'Courier New','Andale Mono',monospace;">call</span><span style="line-height: 1.5;"> (lub </span><span style="font-family: 'Courier New','Andale Mono',monospace;">apply</span><span style="line-height: 1.5;">), tak jak pokazuje ostatni przykład.</span></p>

<div class="note">Więcej na temat <span style="font-family: 'Courier New','Andale Mono',monospace;">this</span> w <a href="/en/JavaScript/Reference/Global_Objects/Function/call" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call">Function#call</a> oraz <a href="/en/JavaScript/Reference/Global_Objects/Function/apply" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply">Function#apply</a></div>

<h4 id="Inheritance" name="Inheritance">Dziedziczenie</h4>

<p>Dziedziczenie jest sposobem na stworzenie klasy jako specjalistycznej wersji jednej lub większej ilości klas (<em>JavaScript wspiera tylko dziedziczenie pojedyncze</em>). Taka wyspecjalizowana klasa jest często nazywana <em>dzieckiem</em>, natomiast ta druga — <em>rodzicem</em>. W JavaScript osiąga się to poprzez przypisanie klasy rodzica do klasy dziecka, a następnie wyspecjalizowaniu jej. W nowoczesnych przeglądarkach można również użyć <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/create#Classical_inheritance_with_Object.create" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/create#Classical_inheritance_with_Object.create">Object.create</a> do implementacji dziedziczenia.</p>

<div class="note">
<p>JavaScript nie wykrywa właściwości klasy dziecka <code>prototype.constructor</code> (zobacz <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/prototype">Core JavaScript 1.5 Reference:Global Objects:Object:prototype</a>), więc musimy tego dokonać ręcznie.</p>
</div>

<p>W poniższym przykładzie definiujemy klasę <code>Student</code> jako dziecko klasy <code>Person</code>. Następnie definiujemy ponownie metodę <code>sayHello()</code> oraz dodajemy metodę <code>sayGoodBye()</code>.</p>

<pre class="brush: js">// Definicja konstruktora Person
function Person(firstName) {
  this.firstName = firstName;
}

// Dodajemy kilka metod do Person.prototype
Person.prototype.walk = function(){
  alert("I am walking!");
};
Person.prototype.sayHello = function(){
  alert("Hello, I'm " + this.firstName);
};

// Definiujemy konstruktor
function Student(firstName, subject) {
  // Wywołujemy konstruktor rodzica (używając Function#call) upewniając się, że "this"
  // <span style="font-size: 1rem;">zostanie ustawione poprawnie podczas wywołania</span>
  Person.call(this, firstName);

  // inicjalizujemy właściwości odpowiednie dla studenta
  this.subject = subject;
};

// Tworzymy obiekt Student.prototype, który dziedziczy po Person
// Uwaga: Typowym błędem w takich przypadkach jest użycie "new Person()" do utworzenia Student.prototype.
// Jest to niepoprawne z kilku powodów, nie wspominając o tym,
// Nie mielibyśmy jakiej wartości podać jako argument "firstName".
// Prawidłowym miejscem na wywołanie konstruktora Person jest to powyżej, w konstruktorze Student
Student.prototype = Object.create(Person.prototype);

// Ustawiamy właściwość "constructor" na obiekt Student
Student.prototype.constructor = Student;

// Zmieniamy metodę "sayHello"
Student.prototype.sayHello = function(){
  alert("Hello, I'm " + this.firstName + ". I'm studying " + this.subject + ".");
};

// Dodajemy metodę "sayGoodBye"
Student.prototype.sayGoodBye = function(){
  alert("Goodbye!");
};

// Przykład użycia:
var student1 = new Student("Janet", "Applied Physics");
student1.sayHello();   // "Hello, I'm Janet. I'm studying Applied Physics."
student1.walk();       // "I am walking!"
student1.sayGoodBye(); // "Goodbye!"

// sprawdzamy poprawność działania "instanceof"
alert(student1 instanceof Person);  // true
alert(student1 instanceof Student); // true
</pre>

<p>Jeśli chodzi o linię <code>Student.prototype = Object.create(Person.prototype);</code> w starszych silnikach JavaScript, nie posiadających metody <a href="/en/JavaScript/Reference/Global_Objects/Object/create" title="Object.create"><code>Object.create</code></a>, można użyć tzw. "polyfill" (aka "shim", patrz artykuł powyżej), czyli funkcję, która stanowi swego rodzaju łatkę zapewniającą kompatybilność wsteczną danej funkcjonalności. Można też samemu napisać funkcję dającą taki sam efekt:</p>

<pre class="brush: js">function createObject(proto) {
    function ctor() { }
    ctor.prototype = proto;
    return new ctor();
}

// Przykład użycia:
Student.prototype = createObject(Person.prototype);
</pre>

<div class="note">Zobacz <a href="/en/JavaScript/Reference/Global_Objects/Object/create" title="Object.create">Object.create</a>, żeby poznać wszystkie jego możliwości oraz znaleźć łatkę dla starszych silników JavaScript.</div>

<h4 id="Encapsulation" name="Encapsulation">Enkapsulacja (hermetyzacja)</h4>

<p>W poprzednim przykładzie klasa <code>Student</code> nie musiała wiedzieć, w jaki sposób metoda <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: 1.5;">walk()</span><span style="line-height: 1.5;"> klasy </span><code style="font-style: normal; line-height: 1.5;">Person</code><span style="line-height: 1.5;"> została zaimplementowana</span><span style="line-height: 1.5;">, ale wciąż mogła jej używać; klasa </span><code style="font-style: normal; line-height: 1.5;">Student</code><span style="line-height: 1.5;"> nie musi ponownie definiować tej metody, dopóki nie chcemy jej zmienić. To zjawisko nazywamy </span><strong style="line-height: 1.5;">enkapsulacją</strong><span style="line-height: 1.5;">, czyli każda klasa dziedziczy metody swojego rodzica i definiuje własne tylko wtedy, gdy chce coś zmienić.</span></p>

<h4 id="Abstraction" name="Abstraction">Abstrakcja</h4>

<p>Abstrakcja jest mechanizmem, który pozwala modelować aktualnie rozpatrywany problem. Może to być osiągane przez dziedziczenie (specjalizację) lub kompozycję. JavaScript osiąga specjalizację dzięki dziedziczeniu, a kompozycję dzięki umożliwieniu instancjom klas bycie wartościami atrybutów innych obiektów.</p>

<p>Klasa Function w JavaScript dziedziczy po klasie Object (jest to przykład specjalizacji modelu), natomiast właściwość Function.prototype jest instancją Object (co z kolei jest przykładem kompozycji).</p>

<pre class="brush: js">var foo = function(){};
alert( 'foo is a Function: ' + (foo instanceof Function) );
alert( 'foo.prototype is an Object: ' + (foo.prototype instanceof Object) );
</pre>

<h4 id="Polymorphism" name="Polymorphism">Polimorfizm</h4>

<p>Tak, jak wszystkie metody i właściwości są zdefiniowane wewnątrz właściwości <code>prototype</code>, tak różne klasy mogą definiować metody z tą samą nazwą; metody mają zasięg ograniczony do klasy, w której zostały zdefiniowane. Ma to rację bytu tylko w przypadku, gdy dwie klasy nie są w relacji rodzic-dziecko (kiedy jedna nie dziedziczy po drugiej w łańcuchu dziedziczenia).</p>

<h2 id="Notes" name="Notes">Uwagi</h2>

<p>Techniki implementacji programowania zorientowanego obiektowo zaprezentowane w tym artykule nie są jedynymi, jakie umożliwia JavaScript, dzięki czemu sposób osiągnięcia programowania obiektowego jest w tym języku bardzo elastyczny.</p>

<p>Techniki tutaj przedstawione nie zawierają żadnych sztuczek językowych, ani nie próbują naśladować implementacji teorii obiektowości z innych języków.</p>

<p>Istnieją inne techniki, które czynią programowanie obiektowe w JavaScript jeszcze bardziej zaawansowanym, jednak są one poza zasięgiem tego artykułu wprowadzającego.</p>

<h2 id="References" name="References">Przypisy</h2>

<ol>
 <li>Mozilla. "<a href="/docs/Web/JavaScript/Guide" title="/docs/Web/JavaScript/Guide">Core JavaScript 1.5 Guide</a>", https://developer.mozilla.org/docs/Web/JavaScript/Guide</li>
 <li>Wikipedia. "Object-oriented programming", <a class="external" href="http://en.wikipedia.org/wiki/Object-oriented_programming" rel="freelink">http://en.wikipedia.org/wiki/Object-...ed_programming</a></li>
 <li><a href="http://davidwalsh.name/javascript-objects">OOP JavaScript Overview</a> series by Kyle Simpson</li>
</ol>