forked from BonsaiDen/JavaScript-Garden
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1911 lines (1453 loc) · 86.5 KB
/
index.html
File metadata and controls
1911 lines (1453 loc) · 86.5 KB
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
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html><html lang="pl"><head><title>JavaScript Garden</title><meta charset="utf-8"><meta name="description" content="Przewodnik po dziwactwach i wadach języka JavaScript."><link rel="stylesheet" href="../style/garden.css" media="all"><link rel="stylesheet" href="../style/print.css" media="print"><!--[if lt IE 9]>
<script src="javascript/html5.js"></script>
<![endif]-->
</head><body><!-- Navigation--><nav id="nav_main"><div><ul><li class="active"><a href="/JavaScript-Garden/pl" title="JavaScript Garden - ogród JavaScript po polsku">pl</a></li><li><a href="/JavaScript-Garden/" title="JavaScript Garden in English">en</a></li><li><a href="/JavaScript-Garden/ru" title="JavaScript Гарден по-русски">ru</a></li><li><a href="/JavaScript-Garden/zh" title="JavaScript Garden 中文翻译">zh</a></li><li><a href="/JavaScript-Garden/tr" title="JavaScript Garden Türkçe">tr</a></li><li><a href="/JavaScript-Garden/es" title="JavaScript Garden es Español">es</a></li><li><a href="/JavaScript-Garden/ja" title="JavaScript Garden in Japanese">ja</a></li><li><a href="/JavaScript-Garden/ko" title="JavaScript Garden">ko</a></li><li><a href="/JavaScript-Garden/fi" title="JavaScript-puutarha suomeksi">fi</a></li></ul><a id="top" href="#intro" title="Back to top">#top</a><a id="hide_menu" class="tablet">Hide Menu</a></div><ul><li class="nav_intro"><h1><a href="#intro">Wstęp</a></h1><ul><li><a href="#intro.authors">Autorzy</a></li><li><a href="#intro.contributors">Współtwórcy</a></li><li><a href="#intro.translators">Tłumaczenie</a></li><li><a href="#intro.hosting">Hosting</a></li><li><a href="#intro.license">Licencja</a></li></ul></li><li class="nav_object"><h1><a href="#object">Obiekty</a></h1><ul><li><a href="#object.general">Wykorzystanie obiektów i ich właściwości</a></li><li><a href="#object.prototype">Prototyp</a></li><li><a href="#object.hasownproperty"><code>hasOwnProperty</code></a></li><li><a href="#object.forinloop">Pętla <code>for in</code></a></li></ul></li><li class="nav_function"><h1><a href="#function">Funkcje</a></h1><ul><li><a href="#function.general">Deklaracje funkcji i wyrażenia funkcyjne</a></li><li><a href="#function.this">Jak działa <code>this</code></a></li><li><a href="#function.closures">Domknięcia i referencje</a></li><li><a href="#function.arguments">Obiekt <code>arguments</code></a></li><li><a href="#function.constructors">Konstruktory</a></li><li><a href="#function.scopes">Zasięg zmiennych i przestrzenie nazw</a></li></ul></li><li class="nav_array"><h1><a href="#array">Tablice</a></h1><ul><li><a href="#array.general">Iterowanie po tablicach oraz właściwościach tablic</a></li><li><a href="#array.constructor">Konstruktor <code>Array</code></a></li></ul></li><li class="nav_types"><h1><a href="#types">Typy</a></h1><ul><li><a href="#types.equality">Równość i porównania</a></li><li><a href="#types.typeof">Operator <code>typeof</code></a></li><li><a href="#types.instanceof">Operator <code>instanceof</code></a></li><li><a href="#types.casting">Rzutowanie typów</a></li></ul></li><li class="nav_core"><h1><a href="#core">Jądro</a></h1><ul><li><a href="#core.eval">Dlaczego nie należy używać <code>eval</code>?</a></li><li><a href="#core.undefined"><code>undefined</code> i <code>null</code></a></li><li><a href="#core.semicolon">Automatyczne wstawianie średnika</a></li></ul></li><li class="nav_other"><h1><a href="#other">Inne</a></h1><ul><li><a href="#other.timeouts"><code>setTimeout</code> i <code>setInterval</code></a></li></ul></li></ul></nav><!-- Mobile navigation--><nav id="nav_mobile"><a id="nav_prev_section" href="#">prev section<span class="nav_section_name">section name</span></a><a id="nav_next_section" href="#">next section<span class="nav_section_name">section name</span></a><a id="show_menu">show menu</a></nav><!-- Sections--><section id="intro"><!-- Introduction--><header id="intro.intro"><h1>Wstęp</h1><div><p><strong>JavaScript Garden</strong> jest rosnącą kolekcją dokumentów o najdziwniejszych
częściach języka JavaScript. Dokumentacja pomaga uniknąć najczęściej popełnianych
błędów, sybtelnych bugów, problemów wydajnościowych oraz złych praktyk, na które
niedoświadczeni programiści JavaScript mogą natrafić próbując poznać tajniki tego
języka.</p>
<p>JavaScript Garden <strong>nie</strong> ma na celu nauczyć Cię języka JavaScript. Podstawowa
wiedza na temat języka jest wymagana do zrozumienia zagadnień poruszanych w tym
przewodniku. Aby nauczyć się podstaw jezyka JavaScript, odwiedź znakomity
<a href="https://developer.mozilla.org/en/JavaScript/Guide">przewodnik</a> na stronach Mozilla Developer Network.</p></div></header><!-- Articles--><article id="intro.authors"><h2>Autorzy</h2><div><p>Ten przewodnik jest dziełem dwóch uroczych użytkowników <a href="http://stackoverflow.com/">Stack Overflow</a>,
<a href="http://stackoverflow.com/users/170224/ivo-wetzel">Ivo Wetzel</a> (Treść) oraz <a href="http://stackoverflow.com/users/313758/yi-jiang">Zhang Yi Jiang</a> (Projekt).</p></div></article><article id="intro.contributors"><h2>Współtwórcy</h2><div><ul>
<li><a href="https://github.com/caio">Caio Romão</a> (Poprawki pisowni)</li>
<li><a href="https://github.com/blixt">Andreas Blixt</a> (Poprawki językowe)</li>
</ul></div></article><article id="intro.translators"><h2>Tłumaczenie</h2><div><ul>
<li><a href="http://qfel13.pl">Łukasz Kufel</a></li>
<li><a href="http://blog.ciemborowicz.pl">Maciej Ciemborowicz</a></li>
</ul></div></article><article id="intro.hosting"><h2>Hosting</h2><div><p>JavaScript Garden znajduje się na serwerach GitHub, ale dzięki wsparciu
<a href="http://cramerdev.com/">Cramer Development</a> posiadamy również mirror na serwerze <a href="http://javascriptgarden.info/">JavaScriptGarden.info</a>.</p></div></article><article id="intro.license"><h2>Licencja</h2><div><p>JavaScript Garden jest publikowany w ramach <a href="https://github.com/BonsaiDen/JavaScript-Garden/blob/next/LICENSE">licencji MIT</a> i kod źródłowy znajduje
się na serwerze <a href="https://github.com/BonsaiDen/JavaScript-Garden">GitHub</a>. Jeśli znajdziesz jakieś błędy lub literówek zgłoś proszę
<a href="https://github.com/BonsaiDen/JavaScript-Garden/issues">problem</a> lub rozwiąż go i zgloś pull request ze swojego repozytorium.
Możesz nas także znaleźć w pokoju <a href="http://chat.stackoverflow.com/rooms/17/javascript">JavaScript</a> na chacie Stack Overflow. </p></div></article></section><section id="object"><!-- Introduction--><header id="object.intro"><h1>Obiekty</h1></header><!-- Articles--><article id="object.general"><h2>Wykorzystanie obiektów i ich właściwości</h2><div><p>Wszystko w JavaScripcie zachowuje sie jak obiekt, z dwoma wyjątkami
<a href="#core.undefined"><code>null</code></a> oraz <a href="#core.undefined"><code>undefined</code></a>. </p>
<pre><code>false.toString() // 'false'
[1, 2, 3].toString(); // '1,2,3'
function Foo(){}
Foo.bar = 1;
Foo.bar; // 1
</code></pre>
<p>Popularnym błędem jest traktowanie literałów liczbowych jak obiektu.
Spowodowane jest to specyfiką parsera JavaScript, który interpretuje kropkę
po literale liczbowym jako rozdzielenie części całkowitej od części ułamkowej
liczby.</p>
<pre><code>2.toString(); // wyrzuca błąd SyntaxError
</code></pre>
<p>Istnieje kilka rozwiązań, dzieki którym literał liczbowy będzie zachowywał się
jak obiekt.</p>
<pre><code>2..toString(); // druga kropka jest poprawnie rozpoznana
2 .toString(); // zauważ, że pozostawiona jest spacja przed kropką
(2).toString(); // 2 zostanie najpierw zewaluowane
</code></pre>
</div><div><h3>Obiekty jako typy danych</h3>
<p>Obiekty w języku JavaScript mogą być używana jako <a href="http://pl.wikipedia.org/wiki/Tablica_asocjacyjna"><em>tablice asocjacyjne</em></a>,
ponieważ obiekty składają się głównie z mapowań pomiędzy nazwanymi właściwościami (kluczami)
a wartościami dla tych atrybutów.</p>
<p>Używając literału obiektu - notacji <code>{}</code> - istnieje możliwość stworzenia obiektu prostego.
Ten nowy obiekt bedzie <a href="#object.prototype">dziedziczył</a> z <code>Object.prototype</code> oraz
nie bedzie posiadał żadnych <a href="#object.hasownproperty">własnych właściwości</a>.</p>
<pre><code>var foo = {}; // nowy, pusty obiekt
// nowy obiekt z właściwością test o wartości 12
var bar = {test: 12};
</code></pre>
</div><div><h3>Dostęp do właściwości</h3>
<p>Właściwości obiektu można uzyskać na dwa sposoby - poprzez notację z kropką
lub z nawiasami kwadratowymi.</p>
<pre><code>var foo = {name: 'Kitten'}
foo.name; // kitten
foo['name']; // kitten
var get = 'name';
foo[get]; // kitten
foo.1234; // wyrzuca błąd SyntaxError
foo['1234']; // działa, zwraca undefined
</code></pre>
<p>Obie notacje są identyczne w swoim działaniu, z tą tylko różnicą, że notacja z nawiasami
kwadratowymi pozwala na dynamiczne dodawanie właściwości i nie prowadzi do wyrzucenia
błędu podczas odczytu nieistniejącej właściwości.</p>
</div><div><h3>Usuwanie właściwości</h3>
<p>Jedynym sposobem na faktycze usunięcie własności z obiektu jest użycie operatora
<code>delete</code>. Ustawienie własności na <code>undefined</code> lub <code>null</code> usunie tylko <em>wartość</em>
związaną z własnością, ale nie usunie to <em>klucza</em> (nazwy własności) z obiektu.</p>
<pre><code>var obj = {
bar: 1,
foo: 2,
baz: 3
};
obj.bar = undefined;
obj.foo = null;
delete obj.baz;
for(var i in obj) {
if (obj.hasOwnProperty(i)) {
console.log(i, '' + obj[i]);
}
}
</code></pre>
<p>Powyższy kod wypisuje dwie linie - <code>bar undefined</code> i <code>foo null</code>. Tylko własność <code>baz</code>
została usunięta i dlatego nie została wypisana.</p>
</div><div><h3>Notacja właściwości</h3>
<pre><code>var test = {
'case': 'jestem słowem kluczowym, więc muszę być w cudzysłowie',
delete: 'tak samo jak ja' // wyrzuca błąd SyntaxError
};
</code></pre>
<p>Nazwy właściwości obiektu mogą być zarówno zapisane jako tekst (bez cudzysłowów
lub apostrofów) lub jako string (w cudzisłowach lub apostrofach).
Ze względu na kolejne niedociągnięcie w parserze JavaScript,
powyższy kod wyrzuci błąd <code>SyntaxError</code> dla implementacji JavaScript ponizej ECMAScript 5.</p>
<p>Ten błąd wynika z faktu, że <code>delete</code> jest <em>słowem kluczowym</em>, dlatego musi zostać
zapisany jako <em>string</em> (z cudzysłowami lub apostrofami), aby zapewnić, że zostanie
to poprawnie zinterpretowane przez starsze silniki języka JavaScript.</p></div></article><article id="object.prototype"><h2>Prototyp</h2><div><p>JavaScript nie posiada klasycznego modelu dziedziczenia. Zamiast tego
dziedziczenie jest realizowane poprzez <em>prototypy</em>.</p>
<p>Choć jest to często uważane za jedną ze słabości języka JavaScript,
prototypowy model dziedziczenia, jest w rzeczywistości potężniejszy od klasycznego
modelu. Na przykład stworzenia klasycznego modelu na podstawie modelu prototypowego
jest dość proste, podczas gdy zrobienie odwrotnego przekształcenie to o wiele trudniejsze zadanie.</p>
<p>Ze względu na fakt, że w JavaScript jest w zasadzie jedynym powszechnie stosowanym
językiem, któy posiada prototypowy model dziedziczenia, dostosowanie się do różnic pomiędzy
tymi dwoma modelami wymaga trochę czasu. </p>
<p>Pierwszą znaczącą różnicą jest to, że dziedziczenie w JavaScript odbywa się za pomocą
tak zwanych <em>łańcuchów prototypów</em>.</p>
<aside>
<p><strong>Uwaga:</strong> Używanie po prostu <code>Bar.prototype = Foo.prototype</code> spowoduje, że oba obiekty
będą korzystały z <strong>tego samego</strong> prototypu. W związku z tym zmiany w prototypie jednego
obiektu będą również zmieniały prototyp drugiego obiektu, co jest ,w wiekszości przypadków,
niepożądanym efektem.</p>
</aside>
<pre><code>function Foo() {
this.value = 42;
}
Foo.prototype = {
method: function() {}
};
function Bar() {}
// Ustawienie prototypu Bar na nową instancję Foo
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';
// Upewniamy się, że Bar jest ustawiony jako rzeczywisty konstruktor
Bar.prototype.constructor = Bar;
var test = new Bar() // tworzymy nową instancję Bar
// The resulting prototype chain
test [instance of Bar]
Bar.prototype [instance of Foo]
{ foo: 'Hello World' }
Foo.prototype
{ method: ... }
Object.prototype
{ toString: ... /* etc. */ }
</code></pre>
<p>W powyższym przykładzie obiekt <code>test</code> będzie dziedziczył z obydwu, tj.
<code>Bar.prototyp</code> i <code>Foo.prototyp</code>, stąd będzie miał dostęp do funkcji <code>method</code>,
która była zdefiniowana w <code>Foo</code>. Ponadto obiekt będzie miał dostęp do
właściwości <code>value</code>, która jest jednyną instancją <code>Foo</code> i stała się jego prototypem.
Należy pamiętać, że <code>new Bar</code> <strong>nie</strong> tworzy nowej instancji <code>Foo</code>,
tylko wykorzystuje instancję, która jest przypisana do własności <code>prototype</code>.
Zatem Wszystkie instancje <code>Bar</code> będą dzieliły tą samą własność <code>value</code>.</p>
<aside>
<p><strong>Uwaga:</strong> <strong>Nie</strong> należy używać konstrukcji <code>Bar.prototype = Foo</code>,
ponieważ nie spowoduje ona przypisania prototypu <code>Foo</code> tylko obiektu
funckji <code>Foo</code>. Zatem łańcuch prototypów nie bedzie zawierał <code>Foo.prototype</code>,
tylko <code>Function.prototype</code>, więc metoda <code>method</code> nie będzie w łańcuchu prototypów. </p>
</aside>
</div><div><h3>Wyszukiwanie własności</h3>
<p>Podczas dostępu do właściwości obiektu JavaScript przejdzie w górę łańcucha
prototypów, dopóki nie znajdzie właściwości bez nazwy.</p>
<p>Gdy przeszukiwanie dotrze do końca (szczytu) łańcucha, mianowicie <code>Object.prototype</code>
i nadal nie znajdzie określonej właściwości, to zwróci wartość
<a href="#core.undefined">undefined</a>. </p>
</div><div><h3>Właściwość prototype</h3>
<p>Podczas gdy właściwość <code>prototype</code> jest używana przez język do budowania łańcucha
prototypów, istnieje możliwość przypisania do niej <strong>dowolnej</strong> wartości. Jednakże
prymitywne typy będą po prostu ignorowanie, jeżeli zostaną ustawione jako <code>prototype</code>.</p>
<pre><code>function Foo() {}
Foo.prototype = 1; // nie ma wpływu
</code></pre>
<p>Przypisywanie obiektów, jak pokazano w powyższym przykładzie, zadziała i pozwala
na dynamiczne tworzenie łańcuchów prototypów.</p>
</div><div><h3>Wydajność</h3>
<p>Czas wyszukiwania właściwości, które są na końcu łańcucha prototypów może mieć
negatywny wpływ na wydajność krytycznych części kodu. Dodatkowo, próba dostępu
do nieistniejącej właściwości zawsze spowoduje przeszukanie całego łańcucha prototypów.</p>
<p>Również podczas <a href="#object.forinloop">iteracji</a> po właściwościach obiektu
<strong>każda</strong> właściwość, która znajduje się w łańcuchu prototypów (niezależnie
na jakim znajduje się poziomie) zostanie wyliczona.</p>
</div><div><h3>Rozszerzanie natywnych prototypów</h3>
<p>Rozszerzanie <code>Object.prototype</code> lub innego prototypu wbudowanych typów jest jednym z
najczęściej nadużywanej częsci języka JavaScript.</p>
<p>Technika ta nazywana jest <a href="http://en.wikipedia.org/wiki/Monkey_patch">monkey patching</a> i łamie zasady <em>enkapsulacji</em>.
Mimo to jest szeroko rozpowszechniona w frameworkach takich jak <a href="http://prototypejs.org/">Prototype</a>.
Nie ma jednak dobrego powodu, aby zaśmiecać wbudowane typy poprzez wzbogacanie ich o
<em>niestandardowe</em> funkcjonalności.</p>
<p><strong>Jedynym</strong> dobrym powodem do rozszerzania wbudowanych prototypów jest portowanie <br />
funkcjonalności znajdujących sie w nowszych silnikach JavaScript, np. <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach"><code>Array.forEach</code></a></p>
</div><div><h3>Wnioski</h3>
<p>Zanim przystąpi się do pisania skomplikowanego kodu korzystającego z dziedziczania, <br />
należy <strong>całkowicie</strong> zrozumieć prototypowy model dziedziczenia. Ponadto trzeba uważać
na długość łańcucha prototypów i w razie potrzeby zmniejszać ilość dziedziczeń,
aby uniknąć problemów z wydajnością. Natywne prototypy <strong>nigdy</strong> nie powinny być
rozszerzane, chyba że ze względu na wprowadzanie kompatybilności z nowszymi silnikami
JavaScript.</p></div></article><article id="object.hasownproperty"><h2><code>hasOwnProperty</code></h2><div><p>W celu sprawdzenia, czy dana właściwość została zdefiniowana <em>w tym</em> obiekcie, a <strong>nie</strong>
w <a href="#object.prototype">łańcuchu prototypów</a>, niezbędne jest skorzystanie z metody
<code>hasOwnProperty</code>, której wszystkie obiekty dziedziczą z <code>Object.prototype</code>.</p>
<aside>
<p><strong>Uwaga:</strong> <strong>Nie</strong> wystarczy sprawdzić, czy właściwość jest <code>undefined</code>,
ponieważ właściwość może istnieć, ale jej wartość być ustawiona na <code>undefined</code>. </p>
</aside>
<p><code>hasOwnProperty</code> jest jedyną metodą w języku JavaScript, która operuje na właściwościach
i <strong>nie</strong> przegląda całego łańcucha prototypów. </p>
<pre><code>// Zatrucie Object.prototype
Object.prototype.bar = 1;
var foo = {goo: undefined};
foo.bar; // 1
'bar' in foo; // true
foo.hasOwnProperty('bar'); // false
foo.hasOwnProperty('goo'); // true
</code></pre>
<p>Tylko <code>hasOwnProperty</code> da prawidłowy i oczekiwany rezultat. Jest to istotne podczas
iteracji po właściwościach obiektu. <strong>Nie</strong> ma innego sposobu na ominięcie
właściwości, która nie została zdefiniowana przez ten <strong>konkretny</strong> obiekt,
ale gdzieś indziej w łańcuchu prototypów. </p>
</div><div><h3><code>hasOwnProperty</code> jako właściwość</h3>
<p>JavaScript <strong>nie</strong> chroni właściwości o nazwie <code>hasOwnProperty</code>, zatem istnieje
możliwość, że obiekt będzie posiadać tak nazwaną właściwość. Konieczne jest użycie
<em>zewnętrznego</em> <code>hasOwnProperty</code>, aby otrzymać poprawne rezultaty.</p>
<pre><code>var foo = {
hasOwnProperty: function() {
return false;
},
bar: 'Here be dragons'
};
foo.hasOwnProperty('bar'); // zawsze zwraca false
// Została użyta metoda innego obiektu i wywołana z konkekstem
// `this` ustawionym na foo
({}).hasOwnProperty.call(foo, 'bar'); // true
</code></pre>
</div><div><h3>Wnioski</h3>
<p><strong>Jedyną</strong> metodą służącą do sprawdzenia istnienia jakiejś właściwości w konkretnym
obiekcie jest metoda <code>hasOwnProperty</code>. Zaleca się korzystać z <code>hasOwnProperty</code> w
<strong>każdej</strong> <a href="#object.forinloop">pętli <code>for in</code></a>. Pozwoli to uniknąć błędów pochodzących
z rozszerzonych natywnych <a href="#object.prototype">prototypów</a>.</p></div></article><article id="object.forinloop"><h2>Pętla <code>for in</code></h2><div><p>Podobnie jak operator <code>in</code>, pętla <code>for in</code> przeszukuje łańcuch prototypów
podczas iteracji po właściwościach obiektu.</p>
<aside>
<p><strong>Uwaga:</strong> pętla <code>for in</code> <strong>nie</strong> będzie iterować po właściwościach, które
mają ustawiony atrybut <code>enumerable</code> na <code>false</code> (na przykład właściwość
<code>length</code> tablicy).</p>
</aside>
<pre><code>// Zatrucie Object.prototype
Object.prototype.bar = 1;
var foo = {moo: 2};
for(var i in foo) {
console.log(i); // wyświetla obie właściwości: bar i moo
}
</code></pre>
<p>Ponieważ zmiana zachowania pętli <code>for in</code> nie jest możliwa, niezbędne
jest odfiltrowanie niechcianych właściwości wewnątrz ciała pętli, korzystając
z metody <a href="#object.hasownproperty"><code>hasOwnProperty</code></a> z <code>Object.prototype</code>.</p>
<aside>
<p><strong>Uwaga:</strong> Ponieważ pętla <code>for in</code> zawsze przeszukuje cały łańcuch prototypów,
będzie się ona stawała coraz wolniejsza przy dodaniu każdej kolejnej warstwy
dziedziczenia do obiektu. </p>
</aside>
</div><div><h3>Filtrowania przy użyciu <code>hasOwnProperty</code></h3>
<pre><code>// foo z przykładu powyżej
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i);
}
}
</code></pre>
<p>To jest jedyna poprawna wersja, której należy używać. Ze względu na użycie
<code>hasOwnProperty</code> zostanie wypisane <strong>jedynie</strong> <code>moo</code>. Gdy opuścimy <code>hasOwnProperty</code>,
kod będzie podatny na błędy, gdy natywne prototypy (np. <code>Object.prototype</code>)
zostaną rozszerzone.</p>
<p><a href="http://www.prototypejs.org/">Prototype</a> jest jednym z popularniejszych frameworków, które dokonują
takiego rozszerzenia. Używanie tego frameworku oraz nie stosowanie w pętli <code>for in</code>
metody <code>hasOwnProperty</code> gwarantuje błędy w wykonaniu.</p>
</div><div><h3>Wnioski</h3>
<p>Zaleca się, aby zawsze używać metody <code>hasOwnProperty</code>. Nigdy nie powinno się dokonywać
żadnych założeń na temat środowiska, w którym kod będzie wykonywany ani tego, czy
natywne prototypy zostały rozszerzone, czy nie.</p></div></article></section><section id="function"><!-- Introduction--><header id="function.intro"><h1>Funkcje</h1></header><!-- Articles--><article id="function.general"><h2>Deklaracje funkcji i wyrażenia funkcyjne</h2><div><p>Funcje w języku JavaScript są <a href="http://pl.wikipedia.org/wiki/Typ_pierwszoklasowy">typami pierwszoklasowymi</a>, co oznacza, że mogą
być przekazywane jak każda inna wartość. Jednym z typowych zastosowań tej cechy
jest przekazywanie <em>anonimowej funkcji</em> jako callback do innej, prawdopodobnie
asynchronicznej funkcji.</p>
</div><div><h3>Deklaracja funckcji</h3>
<pre><code>function foo() {}
</code></pre>
<p>Powyższa funkcja zostaje <a href="#function.scopes">wyniesiona</a> zanim program wystartuje. Dzięki temu
jest dostępna <em>wszędzie</em> w ramach zasięgu, w którym została <em>zadeklarowana</em>,
nawet, jeżeli ta funkcja została wywołana przed faktyczną definicją w kodzie źródłowym.</p>
<pre><code>foo(); // Działa ponieważ definicja funkcji została wyniesiona
// na początek zasięgu przed uruchomieniem kodu
function foo() {}
</code></pre>
</div><div><h3>Wyrażenie funkcyjne</h3>
<pre><code>var foo = function() {};
</code></pre>
<p>Ten przykład przypisuje nienazwaną i <em>anonimową</em> funkcję do zmiennej <code>foo</code>. </p>
<pre><code>foo; // 'undefined'
foo(); // wyrzuca błąd TypeError
var foo = function() {};
</code></pre>
<p>Ze względu na fakt, że deklaracja <code>var</code> wynosi zmienną <code>foo</code> na początek zasięgu
zanim kod faktycznie zostanie uruchomiony, <code>foo</code> będzie zdefiniowane kiedy skrypt
będzie wykonywany.</p>
<p>Ale ponieważ przypisania robione są dopiero podczas wykonania, wartość <code>foo</code> będzie
ustawiona na domyślną wartość <a href="#core.undefined">undefined</a> zanim powyższy kod
zostanie uruchomiony.</p>
</div><div><h3>Nazwane wyrażenia funkcyjne</h3>
<p>Kolejnym specjalnym przypadkiem jest przypisanie nazwanej funkcji. </p>
<pre><code>var foo = function bar() {
bar(); // Działa
}
bar(); // wyrzuca ReferenceError
</code></pre>
<p>W zewnętrznym zakresie <code>bar</code> nie będzie dostępna, ponieważ funkcja zostaje
przypisana do <code>foo</code>, jednakże w wewnętrznym zakresie <code>bar</code> będzie dostępna.
Jest to spowodowane tym, jak działa <a href="#function.scopes">rozwiązywanie nazw</a>
w języku JavaScript. Nazwa funkcji jest <em>zawsze</em> dostępna w lokalnym
zakresie tej funkcji.</p></div></article><article id="function.this"><h2>Jak działa <code>this</code></h2><div><p>JavaScript posiada inną koncepcję odnośnie tego na co wskazuje słowo kluczowe
<code>this</code>, niż większość innych języków programowania. Istnieje dokładnie
<strong>pięć</strong> różnych sytuacji, w których wartość <code>this</code> jest przypisana w języku JavaScript.</p>
<p>JavaScript has a different concept of what the special name <code>this</code> refers to
than most other programming languages do. There are exactly <strong>five</strong> different
ways in which the value of <code>this</code> can be bound in the language.</p>
</div><div><h3>Zasięg globalny</h3>
<pre><code>this;
</code></pre>
<p>Używanie <code>this</code> w globalnym zasięgu, zwróci po prostu referencję do obiektu <em>global</em>.</p>
</div><div><h3>Wywołanie funkcji</h3>
<pre><code>foo();
</code></pre>
<p>Tutaj <code>this</code> również będzie wkazywało na obiekt <em>global</em></p>
<aside>
<p><strong>Uwaga ES5:</strong> W trybie strict mode, przypadki z globalnym zasięgiem nie mają miejsca.
W tym przypadku <code>this</code> zwróci <code>undefined</code> zamiast wartości.</p>
</aside>
</div><div><h3>Wywoływanie metody</h3>
<pre><code>test.foo();
</code></pre>
<p>W tym przypadku <code>this</code> będzie wskazywało na <code>test</code>.</p>
</div><div><h3>Wywołanie konstruktora</h3>
<pre><code>new foo();
</code></pre>
<p>Wywołanie funkcji, które jest poprzedzone słowem kluczowym <code>new</code>, zachowuje się
jak <a href="#function.constructors">konstruktor</a>. Wewnątrz funkcji <code>this</code> będzie
wskazywało na <em>nowo utworzony</em> obiekt.</p>
</div><div><h3>Jawne ustawienie <code>this</code></h3>
<pre><code>function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // tablica zostanie zamieniona w to co poniżej
foo.call(bar, 1, 2, 3); // rezultat a = 1, b = 2, c = 3
</code></pre>
<p>Używając metod <code>call</code> lub <code>apply</code> z prototypu <code>Function.prototype</code>, wartość <code>this</code>
wewnątrz wołanej funkcji zostanie <strong>jawnie ustawiona</strong> na pierwszy argument przekazany
podczas wywołania tych metod.</p>
<p>Zatem w powyższym przykładzie przypadek <em>Wywoływanie metody</em> nie będzie miał
miejsca i <code>this</code> wewnątrz <code>foo</code> będzie wskazywać na <code>bar</code>.</p>
<aside>
<p><strong>Uwaga:</strong> <code>this</code> <strong>nie może</strong> zostać użyte jako referencja do obiektu wewnątrz literału
<code>Object</code>. Zatem <code>var obj = {me: this}</code> <strong>nie</strong> spowoduje, że <code>me</code> będzie wskazywać na <code>obj</code>,
<code>this</code> zostaje związane z wartością tylko w powyższych pięciu wylistowanych przypadkach.</p>
</aside>
</div><div><h3>Częste pułapki</h3>
<p>Mimo iż Większość z tych przypadków ma sens, to pierwszy przypadek powinien być
traktorany jako błąd podczas projektowania języka i <strong>nigdy</strong> nie wykorzystywany
w praktyce.</p>
<pre><code>Foo.method = function() {
function test() {
// wewnątrz tej funkcji this wskazuje na obiekt global
}
test();
}
</code></pre>
<p>Powszechnym błędem jest myślenie, że <code>this</code> wewnątrz <code>test</code> wskazuje na <code>Foo</code>,
podczas gdy w rzeczywistości tak <strong>nie jest</strong>.</p>
<p>Aby uzyskać dostęp do <code>Foo</code> wewnątrz <code>test</code>, niezbędne jest stworzenie wewnątrz
metody lokalnej zmiennej, która będzie wskazywała na <code>Foo</code>.</p>
<pre><code>Foo.method = function() {
var that = this;
function test() {
// Należy używać that zamiast this wewnątrz tej funkcji
}
test();
}
</code></pre>
<p><code>that</code> jest zwykłą zmienną, ale jest to powszechnie stosowana konwencja otrzymywania <br />
wartości zewnętrznego <code>this</code>. W połączeniu z <a href="#function.closures">domknięciami(closures)</a>,
jest to sposób na przekazywanie wartości <code>this</code> wokół.</p>
</div><div><h3>Metody przypisywania</h3>
<p>Kolejną rzeczą, która <strong>nie</strong> działa w języku JavaScript, jest nadawanie aliasów
funkcjom, co oznacza <strong>przypisanie</strong> metody do zmiennej.</p>
<pre><code>var test = someObject.methodTest;
test();
</code></pre>
<p>Podobnie jak w pierwszym przypadku <code>test</code> zachowuje się jak wywołanie zwykłej
funkcji, a zatem wewnątrz funkcji <code>this</code> już nie będzie wskazywało <code>someObject</code>.</p>
<p>Podczas gdy późne wiązanie <code>this</code> może się na początku wydawać złym pomysłem,
to w rzeczywistości jest to rzecz, która sprawia, że
<a href="#object.prototype">dziedziczenie prototypowe</a> działa.</p>
<pre><code>function Foo() {}
Foo.prototype.method = function() {};
function Bar() {}
Bar.prototype = Foo.prototype;
new Bar().method();
</code></pre>
<p>Kiedy metoda <code>method</code> zostanie wywołana na instancji <code>Bar</code>, <code>this</code> będzie
wskazywało właśnie tę instancję.</p></div></article><article id="function.closures"><h2>Domknięcia i referencje</h2><div><p>Jedną z najpotężniejszych funkcjonalności języka JavaScript są <em>domknięcia</em>.
Oznacza to że zasięg <strong>zawsze</strong> posiada dostęp do zewnętrznego zasięgu, w którym
został zdefiniowany. Ponieważ zasięg w JavaScript można definiować tylko poprzez
<a href="#function.scopes">funckję</a>, wszystkie funkcje domyślnie zachowują się jak domknięcia.</p>
</div><div><h3>Emulowanie prywatnych zmiennych</h3>
<pre><code>function Counter(start) {
var count = start;
return {
increment: function() {
count++;
},
get: function() {
return count;
}
}
}
var foo = Counter(4);
foo.increment();
foo.get(); // 5
</code></pre>
<p>Tutaj <code>Counter</code> zwraca <strong>dwa</strong> domknięcia: funkcję <code>increment</code> oraz funkcję <code>get</code>.
Obie te funkcje trzymają <strong>referencję</strong> do zasięgu <code>Counter</code>, a co za tym idzie
zawsze posiadają dostęp do zmiennej <code>count</code> tak, jakby ta zmienna była zdefiniowana
w zasięgu tych funkcji.</p>
</div><div><h3>Dlaczego zmienne prywatne działają?</h3>
<p>Ponieważ nie ma możliwości wskazania lub przypisania zasięgu w JavaScript,
<strong>nie</strong> istnieje sposób, aby uzyskać dostęp do zmiennej <code>count</code> z zewnątrz.
Wykorzystanie tych dwóch domknięć jest jedynym sposobem na interakcję z tą zmienną.</p>
<pre><code>var foo = new Counter(4);
foo.hack = function() {
count = 1337;
};
</code></pre>
<p>Powyższy kod <strong>nie</strong> zmieni wartości zmiennej <code>count</code> wewnątrz zasięgu <code>Counter</code>,
ponieważ <code>foo.hack</code> nie została zadeklarowana wewnątrz <strong>tego konkretnego</strong> zasięgu.
Zamiast tego funkcja utworzy lub nadpisze <em>globalną</em> zmienną <code>count</code>.</p>
</div><div><h3>Domknięcia wewnątrz pętli</h3>
<p>Jednym z częstrzych błędów jest wykorzystywanie domknięć wewnątrz pętli,
aby wartość zmiennej po której odbywa się iteracja była kopiowana do
wewnętrznej funkcji.</p>
<pre><code>for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
</code></pre>
<p>Powyższy kod <strong>nie</strong> wypisze numerów od <code>0</code> do <code>9</code>, ale wypisze
dziesięć razy liczbę <code>10</code>.</p>
<p><em>Anonimowa</em> funkcja trzyma <strong>wskaźnik</strong> do zmiennej <code>i</code> i podczas uruchomienia
<code>console.log</code>, pętla <code>for</code> już zakończyła działanie i wartość zmiennej <code>i</code>
została ustawiona na <code>10</code>.</p>
<p>Aby otrzymać zamierzony efekt, niezbędne jest <strong>skopiowanie</strong> wartości
zmiennej <code>i</code>.</p>
</div><div><h3>Unikanie problemu z referencją</h3>
<p>Aby skopiować wartość zmiennej, po której iterujemy w pętli, należy skorzystać
z <a href="#function.scopes">anonimowego wrappera</a>.</p>
<pre><code>for(var i = 0; i < 10; i++) {
(function(e) {
setTimeout(function() {
console.log(e);
}, 1000);
})(i);
}
</code></pre>
<p>Zewnętrzna anonimowa funkcja zostanie wywołana od razu z parametrem <code>i</code>
jako pierwszym argumentem oraz otrzyma kopię <strong>wartości</strong> zmiennej <code>i</code> jako
zmienną <code>e</code>.</p>
<p>Anonimowa funkcja która zostaje przekazana do <code>setTimeout</code> teraz posiada
referencję do zmiennej <code>e</code>, która nie zostanie zmieniona przez pętle <code>for</code>.</p>
<p>Istnieje jeszcze jeden sposób na osiągnięcie tego samego efektu. Należy zwrócic
fukcję z anonimowego wrappera, wówczas kod będzie zachowywał się jak ten
wcześniejszy.</p>
<pre><code>for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
}
</code></pre></div></article><article id="function.arguments"><h2>Obiekt <code>arguments</code></h2><div><p>Każdy zasięg funkcyjny w języku JavaScript ma dostęp do specjalnej zmiennej <code>arguments</code>.
Ta zmienna trzyma listę wszystkich argumentów przekazanych do funkcji.</p>
<aside>
<p><strong>Uwaga:</strong> W przypadku gdy <code>arguments</code> zostanie zadeklarowana wewnątrz funkcji
poprzez <code>var</code> lub jako nazwa jednego z formalnych parametrów, obiekt <code>arguments</code>
nie zostanie utworzony.</p>
</aside>
<p>Obiekt <code>arguments</code> <strong>nie</strong> jest typu <code>Array</code>. Mimo że posiada pewne cechy
semantyki tablic - właściwość <code>length</code> - to w rzeczywistości nie dziedziczy
on z <code>Array.prototype</code>, tylko z <code>Object</code>.</p>
<p>Ze względu na to, na obiekcie <code>arguments</code> <strong>nie</strong> można używać standardowych dla tablic metod,
takich jak <code>push</code>, <code>pop</code> czy <code>slice</code>. Mimo że iteracja przy pomocy
pętli <code>for</code> działa dobrze, to aby skorzystać ze standardowych metod tablicowych
należy skonwertować <code>arguments</code> do prawdziwego obiekt <code>Array</code>.</p>
</div><div><h3>Konwersja do tablicy</h3>
<p>Poniższy kod zwróci nowy obiekt <code>Array</code> zawierający wszystkie elementy
obiektu <code>arguments</code>.</p>
<pre><code>Array.prototype.slice.call(arguments);
</code></pre>
<p>Jednakże konwersja ta jest <strong>wolna</strong> i <strong>nie jest zalecana</strong> w sekcjach,
które mają duży wpływ na wydajność.</p>
</div><div><h3>Przekazywanie argumentów</h3>
<p>Zalecany sposób przekazywania argumentów z jednej funkcji do następnej
wyglada następująco:</p>
<pre><code>function foo() {
bar.apply(null, arguments);
}
function bar(a, b, c) {
// do stuff here
}
</code></pre>
<p>Kolejną sztuczką jest użycie razem <code>call</code> i <code>apply</code> w celu stworzenia
szybkich i nieograniczonych wrapperów. </p>
<pre><code>function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
// Stworzenie nieograniczoną wersję metody "method"
// która przyjmuje parametry: this, arg1, arg2...argN
Foo.method = function() {
// Rezultat: Foo.prototype.method.call(this, arg1, arg2... argN)
Function.call.apply(Foo.prototype.method, arguments);
};
</code></pre>
</div><div><h3>Parametry formalne i indeksy argumentów</h3>
<p>Obiekt <code>arguments</code> tworzy funkcje <em>getter</em> i <em>setter</em> nie tylko dla swoich
właściwości, ale również dla parametrów formalnych funkcji.</p>
<p>W rezultacie zmiana wartości parametru formalnego zmieni również wartość
odpowiadającemu mu wpisowi w obiekcie <code>arguments</code>. Zachodzi to również w drugą stronę.</p>
<pre><code>function foo(a, b, c) {
arguments[0] = 2;
a; // 2
b = 4;
arguments[1]; // 4
var d = c;
d = 9;
c; // 3
}
foo(1, 2, 3);
</code></pre>
</div><div><h3>Mity i prawdy o wydajności</h3>
<p>Obiekt <code>arguments</code> jest tworzony zawsze, z wyjątkiem dwóch przypadków, gdy
zmienna o takiej nazwie jest zdefiniowana wewnątrz funkcji lub jeden z parametrów
formalnych funkcji ma taką nazwę. Nie ma znaczenia czy obiekt <code>arguments</code> jest
używany czy nie.</p>
<p>Zarówno <em>gettery</em> jak i <em>settery</em> są zawsze tworzone, zatem używanie ich nie ma
praktycznie żadnego wpływu na wydajność. Zwłaszcza w rzeczywistym kodzie, który
wykorzystuje coś więcej niż tylko prosty dostęp do właściwości obiektu <code>arguments</code>. </p>
<aside>
<p><strong>Uwaga ES5:</strong> <em>gettery</em> and <em>settery</em> nie są tworzone w trybie strict mode</p>
</aside>
<p>Jednakże, istnieje jeden przypadek w którym wydajność drastycznie spada w
nowoczesnych silnikach JavaScript. Ten przypadek to wykorzystanie
<code>arguments.callee</code>.</p>
<pre><code>function foo() {
arguments.callee; // operowanie na obiekcie funkcji
arguments.callee.caller; // i obiekcie funkcji wywołującej
}
function bigLoop() {
for(var i = 0; i < 100000; i++) {
foo(); // Normalnie zostałaby wykorzystana metoda inline
}
}
</code></pre>
<p>W powyższym przykładzie <code>foo</code> nie może zostać wykorzystana metoda <a href="http://en.wikipedia.org/wiki/Inlining">inline</a>
ponieważ potrzebne są nie tylko informacje na własny temat ale również
na temat funkcji wywołującej. Takie użycie nie tylko uniemożliwia
inlining i korzyści z niego wynikające, ale też łamie zasady enkapsulacji,
ponieważ ta funkcja jest zależna od kontekstu w jakim została wywołana.</p>
<p><strong>Mocno zalecane</strong> jest aby <strong>nigdy</strong> nie korzystać z <code>arguments.callee</code>
i żadnej jej własności.</p>
<aside>
<p><strong>Uwaga ES5:</strong> W trybie strict mode, <code>arguments.callee</code> wyrzuci <code>TypeError</code>
ponieważ korzystanie z niej jest przestarzałe.</p>
</aside></div></article><article id="function.constructors"><h2>Konstruktory</h2><div><p>Konstruktory w JavaScript również wyglądają inaczej niż innych językach. Każde
wywołanie funkcji, które jest poprzedone słowem kluczowym <code>new</code>, zachowuje się
jak konstruktor. </p>
<p>Wewnątrz konstruktora - wywoływanej fukcji - wartość <code>this</code> wskazuje na
nowo utworzony obiekt <code>Object</code>. Prototyp <a href="#object.prototype"><code>prototype</code></a> tego
<strong>nowego</strong> obiektu będzie wskazywał na prototyp <code>prototype</code> obiektu fukcji,
która została wywołana jako konstruktor.</p>
<p>Jeżeli wywołana funkcja nie posiada jawnej deklaracji <code>return</code>, wówczas
fukcja domyślnie zwraca wartość <code>this</code> - nowy obiekt.</p>
<pre><code>function Foo() {
this.bla = 1;
}
Foo.prototype.test = function() {
console.log(this.bla);
};
var test = new Foo();
</code></pre>
<p>Powyżej wywołanya została funkcja <code>Foo</code> jako konstruktor oraz ustawia
nowo utworzonemu obiektowi właściwość <code>prototype</code> na <code>Foo.prototype</code>.</p>
<p>W tym przypadku jawna deklaracja <code>return</code> w funkcji zwraca wartość
ustawioną w deklaracji, <strong>ale tylko</strong> jeżeli zwracaną wartością jest
obiekt <code>Object</code>.</p>
<pre><code>function Bar() {
return 2;
}
new Bar(); // nowy obiekt
function Test() {
this.value = 2;
return {
foo: 1
};
}
new Test(); // zwrócony obiekt
</code></pre>
<p>Jeżeli słowo kluczowe <code>new</code> zostanie pominięte, funkcja <strong>nie</strong> zwróci nowego
obiektu.</p>
<pre><code>function Foo() {
this.bla = 1; // zostanie ustawiona w obiekcie global
}
Foo(); // undefined
</code></pre>
<p>Mimo że powyższy kod może zadziałać w pewnych przypadkach, w związku
z działaniem <a href="#function.this"><code>this</code></a> w języku JavaScript, to jako
wartość <code>this</code>zostanie wykorzystany <strong>obiekt global</strong>.</p>
</div><div><h3>Fabryki</h3>
<p>Aby móc ominąć słowo kluczowe <code>new</code>, konstruktor musi jawnie zwracać wartość.</p>
<pre><code>function Bar() {
var value = 1;
return {
method: function() {
return value;
}
}
}
Bar.prototype = {
foo: function() {}
};
new Bar();
Bar();
</code></pre>
<p>Oba wywołania <code>Bar</code> zwrócą tę samą rzecz, nowo utworzony obiekt, który posiada
właściwość nazwaną <code>method</code> i dla którego <code>Bar</code> jest <a href="#function.closures">Domknięciem</a>.</p>
<p>Należy również pamiętać, że wywołanie <code>new Bar()</code> <strong>nie</strong> ma wpływu na
prototyp zwróconego obiektu (prototypem będzie <code>object.prototype</code> a nie <code>Bar.prototype</code>).
Kiedy prototyp zostanie przypisany do nowo utworzonego obiektu, <code>Bar</code> nidgy
nie zwróci tego nowego obiektu <code>Bar</code>, tylko literał obiektu, który jest po
słowie kluczowym <code>return</code>.</p>
<p>W powyższym przykładzie nie ma żadnej różnicy w działaniu pomiędzy użyciem
i nieużyciem słowa kluczowego <code>new</code>.</p>
</div><div><h3>Tworzenie nowych obiektów korzystając z fabryk</h3>
<p>Często zaleca się <strong>nie</strong> korzystać z operatora <code>new</code>, ponieważ zapominanie
o jego stosowaniu może prowadzić do błędów.</p>
<p>W celu stworzenia nowego obiektu, powinno się używać fabryki i konstruować
nowy obiekt wewnątrz tej fabryki.</p>
<pre><code>function Foo() {
var obj = {};
obj.value = 'blub';
var private = 2;
obj.someMethod = function(value) {
this.value = value;
}
obj.getPrivate = function() {
return private;
}
return obj;
}
</code></pre>
<p>Mimo że powyższy kod jest odporny na brak słowa kluczowego <code>new</code> i ułatwia
korzystanie ze <a href="#function.closures">zmiennych prywatnych</a>, to posiada
pewne wady.
While the above is robust against a missing <code>new</code> keyword and certainly makes
the use of <a href="#function.closures">private variables</a> easier, it comes with some
downsides.
1. Zużywa więcej pamięci, ponieważ tworzony obiekt <strong>nie</strong> współdzieli metod
poprzez prototyp.
2. Aby móc dziedziczyć fabryka musi skopiować wszystkie metody z dziedziczonego
obiektu lub przypisać ten obiekt, z którego się dziedziczy, jako prototyp
do nowo utworzonego obiektu.
3. Porzucenie łańcucha prototypów tylko ze względu na opuszczone słowo kluczowe
<code>new</code> jest sprzeczne z duchem języka.</p>
</div><div><h3>Wnioski</h3>
<p>Pominięcie słowa kluczowego <code>new</code> może prowadzić do błędów, ale na pewno nie
powinno to być powodem odrzucenia używania prototypów w ogóle. Sprowadza się to
do wyboru rozwiązania, które bardziej pasuje do potrzeb aplikacji. Szczególnie
ważne jest, aby wybrać określony styl tworzenia obiektów i <strong>trzymać</strong> się go.</p></div></article><article id="function.scopes"><h2>Zasięg zmiennych i przestrzenie nazw</h2><div><p>Mimo że JavaScript radzi sobie dobrze ze składnią opisującą dwa pasujące
nawiasy klamrowe jako blok, to jednak <strong>nie</strong> wspiera zasięgu blokowego.
Jedynym zasięgiem jaki istnieje w JavaScript jest <em>zasięg funkcyjny</em>.</p>
<pre><code>function test() { // definiuje zasięg (scope)
for(var i = 0; i < 10; i++) { // nie definiuje zasięgu (scope)
// count
}
console.log(i); // 10
}
</code></pre>
<aside>
<p><strong>Uwaga:</strong> Jeżeli notacja <code>{...}</code> nie jest użyta w przypisaniu, deklaracji return
lub jako argument funkcji, to zostanie zinterpretowana jako deklaracja bloku,
a <strong>nie</strong> jako literał obiektu. W połączeniu z <a href="#core.semicolon">automatycznym wstawianiem średnika</a>,
może prowadzić do subtelnych błędów.</p>
</aside>
<p>W JavaScripcie nie ma również przestrzeni nazw, co oznacza, że wszystko jest
definiowane w jednej <em>globalnie współdzielonej</em> przestrzeni nazw. </p>
<p>Z każdym odwołaniem do zmiennej, JavaScript przeszukuje w górę wszystkie zasięgi
dopóki nie znajdzie tej zmiennej. W przypadku, gdy przeszukiwanie dotrze do globalnego
zasięgu i nadal nie znajdzie żądanej nazwy, to wyrzuca błąd <code>ReferenceError</code>.</p>
</div><div><h3>Zmora globalnych zmiennych</h3>
<pre><code>// script A
foo = '42';
// script B
var foo = '42'
</code></pre>
<p>Powyższe dwa skrypty <strong>nie</strong> dają tego samego efektu. Skrypt A definiuje zmienną
nazwaną <code>foo</code> w <em>globalnym</em> zasięgu, natomiast skrypt B definiuje <code>foo</code>
w <em>aktualnym</em> zasięgu.</p>
<p>Jeszcze raz, to wcale nie daje <em>tego samego efektu</em>. Nie użycie <code>var</code> może mieć
poważne konsekwencje.</p>
<pre><code>// globalny zasięg
var foo = 42;
function test() {
// lokalny zasięg
foo = 21;
}
test();
foo; // 21
</code></pre>
<p>Pominięcie słowa <code>var</code> w deklaracji wewnątrz funkcji <code>test</code> nadpisze wartość
zmiennej globalnej <code>foo</code>. Mimo że nie wygląda to na początku na duży problem,
posiadanie wielu tysięcy linii kodu w JavaScript i nie korzystanie z <code>var</code>
wprowadzi straszne i trudne do wyśledzenia błędy.</p>
<pre><code>// globalny zasięg
var items = [/* jakaś lista */];
for(var i = 0; i < 10; i++) {
subLoop();
}
function subLoop() {
// scope of subLoop
for(i = 0; i < 10; i++) { // brakuje słowa var w deklaracji
// do amazing stuff!
}
}
</code></pre>
<p>Zewnętrzna pętla zakończy działanie po pierwszym wywołaniu <code>subLoop</code>, ponieważ
<code>subLoop</code> nadpisuje wartość globalnej zmiennej <code>i</code>. Użycie <code>var</code> w drugiej pętli
<code>for</code> pozwoliłoby łatwo uniknąć problemu. Słowo kluczowe <code>var</code> nie powinno być
<strong>nigdy</strong> pominięte w deklaracji, chyba że <em>pożądanym skutkiem</em> jest wpłynięcie na
zewnętrzny zasięg.</p>
</div><div><h3>Lokalne zmienne</h3>
<p>Jedynym źródłem zmiennych lokalnych w JavaScripcie są parametry <a href="#function.general">funkcji</a>
oraz zmienne zadeklarowane poprzez deklaracje <code>var</code> wewnątrz funkcji.</p>
<pre><code>// globalny zasięg
var foo = 1;
var bar = 2;
var i = 2;
function test(i) {
// lokalny zasięg fukcji test
i = 5;
var foo = 3;
bar = 4;
}
test(10);
</code></pre>
<p>Zmienne <code>foo</code> oraz <code>i</code> są lokalnymi zmiennymi wewnątrz zasiegu funkcji <code>test</code>,
natomiast przypisanie wartości do <code>bar</code> nadpisze zmienną globalną o tej samej nazwie.</p>
</div><div><h3>"Hoisting" - wywindowanie, podnoszenie</h3>
<p>JavaScript <strong>winduje</strong> deklaracje. Oznacza to, że zarówno deklaracja ze słowem
kluczowym <code>var</code> jak i deklaracje funkcji <code>function</code> zostaną przeniesione na
początek otaczającego zasięgu.</p>
<pre><code>bar();
var bar = function() {};
var someValue = 42;
test();
function test(data) {
if (false) {
goo = 1;
} else {
var goo = 2;