diff options
Diffstat (limited to 'files/pl/web/javascript/a_re-introduction_to_javascript/index.html')
-rw-r--r-- | files/pl/web/javascript/a_re-introduction_to_javascript/index.html | 966 |
1 files changed, 966 insertions, 0 deletions
diff --git a/files/pl/web/javascript/a_re-introduction_to_javascript/index.html b/files/pl/web/javascript/a_re-introduction_to_javascript/index.html new file mode 100644 index 0000000000..f71457a70d --- /dev/null +++ b/files/pl/web/javascript/a_re-introduction_to_javascript/index.html @@ -0,0 +1,966 @@ +--- +title: Ponowne wprowadzenie do JavaScript (JS tutorial) +slug: Web/JavaScript/A_re-introduction_to_JavaScript +translation_of: Web/JavaScript/A_re-introduction_to_JavaScript +original_slug: Web/JavaScript/Ponowne_wprowadzenie_do_JavaScript +--- +<div>{{jsSidebar}}</div> + +<div></div> + +<div>Po co ponowne wprowadzanie? Ponieważ {{Glossary("JavaScript")}} osławiony jest jako <a href="http://crockford.com/javascript/">najbardziej niezrozumiany język świata</a>. Często wyśmiewany jest jako bycie zabawką, jednak pod warstwą jego prosoty czekają potężne funkcje. Obecnie JavaScript używany jest w niewiarygodnie dużej ilości wysokoprofilowych aplikacji, pokazując, że dogłębne zrozumienie tej technologii jest ważną umiejętnością dla każdego, webowego jak i mobilnego, dewelopera.</div> + +<div></div> + +<div>Warto rozpocząć od zaznajomienia się z historią tego języka. JavaScript został stworzony w 1995 roku przez Brendah Eich, który w tym czasie był inżynierem w Netscape. Pierwszy raz JavaScript został wydany z Netscape 2 początkiem 1996 roku. Pierwotnie miał on być nazywany LiveScript, został jednak przemianowany za sprawą feralnej decyzji marketingowej, która miała na celu wykorzystanie popularności języka Java Sun Microsystem - pomijając znikome części wspólne. Od tego czasu jest to źrodłem wielu nieporozumień. </div> + +<div></div> + +<div>Kilka miesięcy poźniej Microsoft wydał JScript razem z Internet Explorer 3. Był to w większości kompatybilny i podobny w pracy do JavaScript. Kilka miesięcy po tym, Netscape zgłosił JavaScript do <a href="http://www.ecma-international.org/">Ecma International</a>, europejskiego stowarzyszenia standaryzującego, czego rezultatem było wydanie pierwszej edycji {{Glossary("ECMAScript")}}. Standard otrzymał znaczącą aktualizację jako <a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript edition 3</a> w 1999 roku i od tego czasu został prawie niezmieniony. Czwarta edycja została porzucona z powodu różnic politycznych dotyczących złożoności języka. Wiele części czwartej edycji uformowało podstawy dla piątej ECMAScript - opublikowanej w grudniu 2009 roku, oraz szóstej, której publikacja wypadła w czerwcu 2015 roku.</div> + +<div></div> + +<div></div> + +<div class="note"> +<p>Od tej pory określenie "JavaScript" będzie używane w odniesieniu do ECMAScript, ponieważ określenie to jest bardziej rozpoznawalne.</p> +</div> + +<p>W odróżnieniu od innych języków programowania, JavaScript nie posiada koncepcji wejścia ani wyjścia. Zaprojektowany został do działania jako język skryptowy działający w środowisku hosta i do tego środowiska nalezy zapewnienie mechanizmów komunikacji ze światem. Najbardziej pospolitym środowiskiem jest przeglądarka, jednak interpretatory JavaScript można znaleźć również w wielu innych miejscach włączając w to Adobe Acrobat, Adobe Photoshop, obrazy SVG, silnik wigetów Yahoo, w środowiskach uruchomieniowych takich jak <a href="http://nodejs.org/">Node.js</a>, bazach danych NoSQL - <a href="http://couchdb.apache.org/">Apache CouchDB</a>, systemach wbudowanych czy kompletnych środowiskach graficznych takich jak <a href="http://www.gnome.org/">GNOME </a>( jeden z najpopularniejszych GUI dla systemów operacyjnych GNU/Linux ).</p> + +<h2 id="Przegląd">Przegląd</h2> + +<p>JavaScript jest wieloparadygmatowym, dynamicznym językiem z typami i operatorami, standardowymi wbudowanymi obiektami oraz metodami. Jego składnia opiera się na językach Java i C - wiele struktur tych języków również zostało wprowadzonych do JavaScript-u. JavaScript wspiera programowanie obiektowe z prototypami obiektów zamiast klas ( zobacz więcej <a href="https://developer.mozilla.org/pl/docs/Web/JavaScript/dziedziczenie_lancuch_prototypow">dziedziczenie prototypowe</a> oraz <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">ES2015 klasy</a> (ang.)). Dodatkowo JavaScript wspiera programowanie funkcyjne - funkcje są obiektami, nadanie funkcjom możliwości przechowywania kodu wykonawczego i przekazywaniu go jak każdemu innemu obiektowi.</p> + +<p>Zacznijmy od spojrzenia na budulec każdego języka: typy. Programy JavaScript manipulują wartościami, a wszystkie te wartości należą do typu. W JavaScript wyróżniamy typy: </p> + +<ul> + <li>{{jsxref("Number")}}</li> + <li>{{jsxref("String")}}</li> + <li>{{jsxref("Boolean")}}</li> + <li>{{jsxref("Function")}}</li> + <li>{{jsxref("Object")}}</li> + <li>{{jsxref("Symbol")}} (new in ES2015)</li> +</ul> + +<p>...oraz {{jsxref("undefined")}} i {{jsxref("null")}}, które są nieco dziwne. Obiekty posiadają specjalne rodzaje, więc aby być technicznie poprawnym powyższa lista powinna wyglądać następująco:</p> + +<ul> + <li>{{jsxref("Number")}}</li> + <li>{{jsxref("String")}}</li> + <li>{{jsxref("Boolean")}}</li> + <li>{{jsxref("Symbol")}} (new in ES2015)</li> + <li>{{jsxref("Object")}} + <ul> + <li>{{jsxref("Function")}}</li> + <li>{{jsxref("Array")}}</li> + <li>{{jsxref("Date")}}</li> + <li>{{jsxref("RegExp")}}</li> + </ul> + </li> + <li>{{jsxref("null")}}</li> + <li>{{jsxref("undefined")}}</li> +</ul> + +<p>Istnieją także wbudowane typy {{jsxref("Error")}}. Będzie prościej jeśli będziemy trzymać się pierwszej listy, a więc omówione zostaną wymienione tam typy.</p> + +<h2 id="Liczby">Liczby</h2> + +<p>Zgodnie ze specyfikacją numery w JavaScript są "wartościami podwójnie precyzyjnymi 64-bitowego formatu IEEE 754". Ma to pewne interesujące konsekwencje. W JavaScript nie ma rzeczy takiej jak liczba całkowita, należy więc być dość ostrożnym z artmetyką jeśli jesteś przyzywczajony do matematyki w języku C lub Java.</p> + +<p>Dodatkowo, zwracaj uwagę na rzeczy takie jak: </p> + +<pre class="brush: js">0.1 + 0.2 == 0.30000000000000004; +</pre> + +<p>W praktyce, liczby całkowite są traktowane jako 32-bitowe jednostki, a niektóre implementacje przechowują je w ten sposób dopóki nie zostaną poproszone o wykonanie instrukcji, która jest poprawna dla liczby, ale nie dla 32-bitowej liczby całkowitej. Może to być istotne dla operacji bitowych.</p> + +<p>Standardowe<a href="/en-US/docs/Web/JavaScript/Reference/Operators#Arithmetic_operators"> operatory arytmetyczne</a> są wspierane, wliczając w to dodawanie, odejmowanie, modulo i tak dalej. Istnieje też wbudowany obiekt, o którym zapomnieliśmy wspomnieć, {{jsxref("Math")}}, który zapewnia zaawansowane funkcje i stałe matematyczne:</p> + +<pre class="brush: js">Math.sin(3.5); +var circumference = 2 * Math.PI * r; +</pre> + +<p>Możesz zamienić String na liczbę całkowitą używając wbudowanej funkcji {{jsxref("Global_Objects/parseInt", "parseInt()")}}. Funkcja ta przyjmuje podstawę do konwersji jako opcjonalny drugi argument, który zawsze należy podawać:</p> + +<pre class="brush: js">parseInt('123', 10); // 123 +parseInt('010', 10); // 10 +</pre> + +<p>W starszych przeglądarkach, String-i zaczynające się od "0" przyjmowane są w formacie ósemkowym (podstawa 8), jednak od 2013 roku nie stanowiło to problemu. Chyba, że jesteś pewien formatu String-a, mogą zaskoczyć Cię wyniki w starszych przeglądarkach:</p> + +<pre class="brush: js">parseInt('010'); // 8 +parseInt('0x10'); // 16 +</pre> + +<p>Widzimy tu, że funkcja {{jsxref("Global_Objects/parseInt", "parseInt()")}} traktuje pierwszego Stringa w systemie ósemkowym przez 0 na przodzie, drugi String natomiast traktowny jest w systemie szesnastowym przez "0x" z przodu. <em>Zapis szesnastkowy nadal istnieje</em>; tylko ósemkowy został usunięty.</p> + +<p>Jeśli chcesz zmenić liczbę binarną na całkowitą, wystarczy zmienić podstawę:</p> + +<pre class="brush: js">parseInt('11', 2); // 3 +</pre> + +<p>Podobnie możemy przekształcić liczbę zmiennoprzecinkową używając wbudowanej funckcji {{jsxref("Global_Objects/parseFloat", "parseFloat()")}}. W odróżnieniu do {{jsxref("Global_Objects/parseInt", "parseInt()")}}, <code>parseFloat()</code> zawsze uzywa 10 jako podstawy.</p> + +<p>Możesz użyć działania jednoargumentowego <code>+</code>, aby zamienić wartości na liczby:</p> + +<pre class="brush: js">+ '42'; // 42 ++ '010'; // 10 ++ '0x10'; // 16 +</pre> + +<p>Specjalna wartość {{jsxref("NaN")}} ( skrót od "Not a Number" ( ang. nie numer )) zostaje zwrócona jeśli String nie jest liczbowy:</p> + +<pre class="brush: js">parseInt('hello', 10); // NaN +</pre> + +<p><code>NaN</code> jest toksyczny: jesli podasz go jako argument operacji matematycznej jej wynikiem również będzie <code>NaN</code>:</p> + +<pre class="brush: js">NaN + 5; // NaN + +</pre> + +<p>Możesz wykorzystać <code>NaN</code> do testów używając wbudowanej funkcji {{jsxref("Global_Objects/isNaN", "isNaN()")}}:</p> + +<pre class="brush: js">isNaN(NaN); // true + +</pre> + +<p>JavaScript dostarcza również specjalną wartość {{jsxref("Infinity")}} oraz <code>-Infinity</code>:</p> + +<pre class="brush: js"> 1 / 0; // Infinity +-1 / 0; // -Infinity + +</pre> + +<p><code>Infinity</code>, <code>-Infinity</code> oraz <code>NaN </code>wykorzystane mogą być do testów za pomocą wbudowanej funkcji {{jsxref("Global_Objects/isFinite", "isFinite()")}}:</p> + +<pre class="brush: js">isFinite(1 / 0); // false +isFinite(-Infinity); // false +isFinite(NaN); // false +</pre> + +<div class="note">Funkcje {{jsxref("Global_Objects/parseInt", "parseInt()")}} i {{jsxref("Global_Objects/parseFloat", "parseFloat()")}} przekształcają String dopóki nie napotkają znaku, który nie spełnia wymagań formatu liczbowego, po napotkaniu takiego znaku zwrócona zostanie liczba przekształcona do tego momentu. Jednak operator "+" zwyczajnie zwróci <code>NaN</code> jeśli w przekształcanym Stringu znajduje się niepoprawny znak. Spróbuj przekształcić String "10.2abc" używając przedstawionych metod, aby lepiej zrozumieć ich rożnice.</div> + +<h2 id="Strings">Strings</h2> + +<p>String-ami w JavaScript są sekwencje <a href="/en-US/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Unicode">znaków Unicode</a>. To powinna być dobra wiadomość dla każdego kto miał do czynienia z internacjonalizacją. Dokładniej, są to sekwencje jednostek kodowych UTF-16; każda jednostka kodowa jest reprezentowana przez 16-bitową liczbę. Każdy znak Unicode reprezentowany jest przez 1 lub 2 jednostki kodu.</p> + +<p>Jeśli chcesz przekazać jeden znak, musisz poprostu użyć String-a składającego się z tego pojedyńczego znaku.</p> + +<p>Aby sprawdzić długość String-a (w jednostkach kodu), użyj właściwości <a href="https://developer.mozilla.org/pl/docs/Web/JavaScript/Referencje/Obiekty/String/length">length</a>:</p> + +<pre class="brush: js">'hello'.length; // 5 +</pre> + +<p>To było nasza pierwsza styczność z obiektami JavaScript! Wspominaliśmy, że możesz traktować String-i jak {{jsxref("Object", "obiekty", "", 1)}}? Też posiadają one {{jsxref("String", "metody", "#Methods", 1)}}, które pozwalają nimi manipulować i uzyskiwać informacje na ich temat:</p> + +<pre class="brush: js">'hello'.charAt(0); // "h" +'hello, world'.replace('hello', 'goodbye'); // "goodbye, world" +'hello'.toUpperCase(); // "HELLO" +</pre> + +<h2 id="Inne_typy">Inne typy</h2> + +<p>JavaScript odróżnia {{jsxref("null")}}, który jest wartością wskazujacą na umyślny brak wartości ( dostęp do nich tylko za pomocą słowa kluczowego <code>null</code> ), od {{jsxref("undefined")}}, która jest wartością typu <code>undefinded</code>, wskazującą na niezainicjowaną wartość - oznacza to, że wartość nie została jeszcze przypisana. Zmienne zostaną omówione później, narazie wystarczy nam wiedza, że w JavaScripcie możliwe jest zdeklarowanie zmiennej bez przypisania do niej wartości. Jeśli to zrobimy zmienna będzie typu <code>undefinded</code>. <code>undefinded</code> jest w rzeczywistości stałą.</p> + +<p>JavaScript posiada boolean (logiczny typ danych) z możliwymi wartościami <code>true</code> lub <code>false</code> (obie są słowami kluczowymi). Każda wartość może zostać przekonwertowana na typ logiczny zgodnie z zasadami:</p> + +<ol> + <li><code>false</code>, <code>0</code>, pusty string (<code>""</code>), <code>NaN</code>, <code>null</code>, oraz <code>undefined</code> wszystkie odpowiadają <code>false</code>.</li> + <li>Wszystkie inne odpowiadają <code>true</code>.</li> +</ol> + +<p>Możesz wykonać jawną konwersję używając wbudowanej funkcji <code>Boolean()</code>:</p> + +<pre class="brush: js">Boolean(''); // false +Boolean(234); // true +</pre> + +<p>Jednak, tego typu zamiana jest rzadko potrzeba, ponieważ JavaScript automatycznie wykona konwersję, kiedy oczekiwać będzie typu logicznego jak na przykład w przypadku instrukcji warunkowej <code>if</code> (zobacz niżej). Z tego powodu czasami mówi się o "wartościach prawdziwych" (<em>true values</em>) i "wartościach fałszywych" (<em>false value</em>), które oznaczają wartości, które po konwersji na typ logiczny stają się, odpowienio, prawdziwe lub fałszywe. Alternatywnie wartości te nazywane mogą być "truthy" lub "falsy".</p> + +<p>Operatory logiczne takie jak <code>&&</code>( i <em>)</em>, <code>||</code>( lub ) oraz <code>!</code>( negacja ) są wspierane; zobacz niżej.</p> + +<h2 id="Zmienne">Zmienne</h2> + +<p>Do deklaracji nowej zmiennej w JavaScript używamy jednego z trzech słów kluczowych: <a href="/en-US/docs/Web/JavaScript/Reference/Statements/let">let</a>, <a href="/en-US/docs/Web/JavaScript/Reference/Statements/const">const</a> lub <a href="/en-US/docs/Web/JavaScript/Reference/Statements/var">var</a>.</p> + +<p><code><strong>let</strong></code><strong> </strong>pozwala na deklarację zmiennej blokowej. Zadeklarowana zmienna dostępna jest z poziomu <em>bloku, </em>w którym została zadeklarowana.</p> + +<pre class="brush: js">let a; +let name = 'Simon'; + +</pre> + +<p>Poniżej znajduje się przykład zakresu ze zmienną zadeklarowaną za pomocą <code><strong>let</strong></code>:</p> + +<pre class="brush: js">// mojaZmiennaLet *nie* jest tutaj widoczna + +for (let mojaZmiennaLet = 0; mojaZmiennaLet < 5; mojaZmiennaLet++) { + // mojaZmiennaLet jest widoczna tylko tutaj +} + +// mojaZmiennaLet *nie* jest tutaj widoczna +</pre> + +<p><code><strong>const</strong></code><strong> </strong>pozwala zadeklarować zmienne, których wartości z założenia są stałe. Zmienna dostępna jest z <em>bloku,</em> w którym została zadeklarowana.</p> + +<pre class="brush: js">const Pi = 3.14; // deklaruje zmienną Pi +Pi = 1; // zwrócony zostanie błąd ponieważ nie można zmieniać zmiennej <code>const</code></pre> + +<p><strong><code>var</code> </strong>jest najczęściej deklarowaną zmienną. W odróżnieniu do dwóch pozostałych zmiennych nie posiada ograniczeń. Jest tak dlatego, że tradycyjnie był to jedeny sposób deklarowania zmiennych w JavaScript. Zmienna zadeklarowana przy użyciu <strong><code>var</code></strong> dostepna jest z <em>funkcji, </em>w której została zadeklarowana.</p> + +<pre class="brush: js">var a; +var name = 'Simon'; +</pre> + +<p>Przykład zakresu zmiennej zadeklarowanej za pomocą <strong><code>var</code>:</strong></p> + +<pre class="brush: js">// mojaZmiennaVar *jest* tutaj widoczna + +for (var mojaZmiennaVar = 0; mojaZmiennaVar < 5; mojaZmiennaVar++) { + // mojaZmiennaVar jest widoczna dla całej funckji +} + +// mojaZmiennaVar *jest* tutaj widoczna +</pre> + +<p>Jesli zadeklarujesz zmienną bez przypisania do niej wartości, jej typ stanie się <code>undefinded</code>.</p> + +<p>Ważną różnicą między JavaScript i innymi językami, jak Java, jest fakt, że w JavaScript bloki nie mają zasiegu; tylko funkcje posiadają zasięg. Więc jeśli zmienna zostanie zadeklarowana przy użyciu <code>var</code> w złożonej deklaracji (na przykład wewnątrz instrukcji warunkowej <code>if</code>), będzie ona widoczna dla całej funkcji. Jednak, korzystając ze składni ECMAScript 2015, deklaracje <a href="/en-US/docs/Web/JavaScript/Reference/Statements/let">let</a> i <a href="/en-US/docs/Web/JavaScript/Reference/Statements/const">const</a> pozwalają na tworzenie zmiennych o <u>zasięgu blokowym</u>.</p> + +<h2 id="Operatory">Operatory</h2> + +<p>Operatory liczbowe w JavaScript to <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code> oraz <code>%</code>, który jest operatorem reszty (<a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Remainder_%28%29">co nie jest tym samym co modulo</a>). Do przypisania wartości używamy =, istnieje także przypisanie złożone jak na przykład += i -=. Ich rozwinięcie to <code>x = x operator y</code></p> + +<p>x += 5;<br> + x = x + 5;</p> + +<p>Możesz użyć operatorów <code>++</code> aby inkrementować oraz <code>--</code> aby dekrementować. Mogą one być używane zarówno jako operatory prefiksowe lub przyrostkowe.</p> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Addition">Operator +</a> dodatkowo używany jest do łączenia string-ów.</p> + +<pre class="brush: js">'hello' + ' world'; // "hello world" + +</pre> + +<p>Jeśli dodasz string do numeru (lub innej wartości) wszystko zostanie przekształcone w string. Przykład poniżej:</p> + +<pre class="brush: js">'3' + 4 + 5; // "345" + 3 + 4 + '5'; // "75" +</pre> + +<p>Dodanie do czegoś pustego string-a jest przydatnym sposobem na zamiane tego w string. </p> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators">Porówniania</a> w JavaScript wykonywane są za pomocą <code><</code>, <code>></code>, <code><=</code> oraz <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">>=</span></font>. Działają one zarówno ze string-ami jak i numerami. Równość jest trochę mniej prosta. Podwójny operator równości wykonuje przymusowe sprawdzenie kiedy podane zostały wartości o dwóch różnych typach, co czasami może dawać interesujące wyniki:</p> + +<pre class="brush: js">123 == '123'; // true +1 == true; // true + +</pre> + +<p>Aby uniknąć przymusowego sprawdzenia, użyj potrójnego operatora równości:</p> + +<pre class="brush: js">123 === '123'; // false +1 === true; // false +</pre> + +<p>Dodatkowo występują operatory <code>!=</code> oraz <code>!==</code>.</p> + +<p>JavaScript posiada również <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators">operacje bitowe</a>.</p> + +<h2 id="Struktury_kontroli">Struktury kontroli</h2> + +<p>JavaScript posiada podobny zestaw struktur kontorli do innych języków rodziny C. Instrukcje warunkowe są wspierane przez <code>if</code> oraz <code>else</code>; jeśli chcesz możesz je ze sobą łączyć:</p> + +<pre class="brush: js">var name = 'kotki'; +if (name == 'pieski') { + name += ' hau'; +} else if (name == 'kotki') { + name += ' miau'; +} else { + name += '!'; +} +name == 'kotki miau'; +</pre> + +<p>JavaScript ma pętle <code>while</code> i <code>do-while</code>. Pierwsza jest dobra do prostych pętli; druga, jeśli chcesz mieć pewność, że funkcja zostanie wykonana przynajmniej raz:</p> + +<pre class="brush: js">while (true) { + // an infinite loop! +} + +var input; +do { + input = get_input(); +} while (inputIsNotValid(input)); +</pre> + +<p>W JavaScript pętla <code>for</code> działa w taki sam sposób jak w C i Java: pozwala na zapewnienie informacji dla pętli w jednej lini.</p> + +<pre class="brush: js">for (var i = 0; i < 5; i++) { + // Will execute 5 times +} +</pre> + +<p>JavaScript dodatkowo posiada dwie inne znaczące pętle for: <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...of">for...of</a></p> + +<pre class="brush: js">for (let value of array) { + // działania na value +} +</pre> + +<p>oraz <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...in"><code>for</code>...<code>in</code></a>:</p> + +<pre class="brush: js">for (let własność in obiekt) { + // działania na własności obiektu +} +</pre> + +<p>Operatory <code>&&</code> oraz <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">|<code>|</code></span></font> w których wykonanie drugiego operanda zależne jest od pierwszego. Przydatne do sprawdzania istnienia obiektu przed przypisaniem do niego atrybutów:</p> + +<pre class="brush: js">var name = o && o.getName(); + +</pre> + +<p>Lub do cachowania wartości (kiedy wartości nieprawdziwe są nieprawidłowe):</p> + +<pre class="brush: js">var name = cachedName || (cachedName = getName()); +</pre> + +<p>JavaScript posiada potrójny operator dla wyrażeń warunkowych:</p> + +<pre class="brush: js">var allowed = (age > 18) ? 'yes' : 'no'; +</pre> + +<p>Warunek <code>switch</code> może być używany dla wielu odgałęzień na podstawie liczby lub ciągu znaków:</p> + +<pre class="brush: js">switch (action) { + case 'draw': + drawIt(); + break; + case 'eat': + eatIt(); + break; + default: + doNothing(); +} +</pre> + +<p>Jeśli nie dodasz warunku <code>break</code>, wykonanie "przeskoczy" do następnego warunku. Takie działanie jest bardzo rzadko pożądane - w rzeczywistości warto opisać celowy "przeskok" w komentarzu w celu ułatwienia debugowania:</p> + +<pre class="brush: js">switch (a) { + case 1: // przeskok + case 2: + eatIt(); + break; + default: + doNothing(); +} +</pre> + +<p>Domyślny (<code>default</code>) warunek jest opcjonalny. Możesz mieć wyrażenia zarówno w części przełącznika (<code>switch</code>), jak i w przypadku (<code>case</code>); porównania między nimi odbywają się przy pomocy operatora <code>===</code>: </p> + +<pre class="brush: js">switch (1 + 3) { + case 2 + 2: + yay(); + break; + default: + neverhappens(); +} +</pre> + +<h2 id="Obiekty">Obiekty</h2> + +<p>Obiekty w JavaScript można opisać jako prostą kolekcję par nazwa-wartość. Jako takie podobne są do:</p> + +<ul> + <li>Słowniki w Pythonie.</li> + <li>Tablic asocjacyjnych w Perl i Ruby.</li> + <li>Tablic asocjacyjnych w C i C++.</li> + <li>Map w Javie.</li> + <li>Tablic asocjacyjnych w PHP.</li> +</ul> + +<p>Ze względu na popularność tej struktury danych są one świadectwem wszechstronności. Ponieważ wszystko (poza typami prostymi) jest traktowane w JavaScript jak obiekt, każdy program JavaScript naturalnie objemuje dużą ilość wyszukiwań w tablicach mieszających. Dobrze, że są one takie szybkie!</p> + +<p>Część "nazwa" jest stringiem, natomiast wartość może być każdą wartością JavaScript- nawet kolejnym obiektem. Pozwala to na budowanie struktur danych o dowolnej złożoności.</p> + +<p>Istnieją dwa podstawowe sposoby tworzenia pustego obiektu:</p> + +<pre class="brush: js">var obj = new Object(); +</pre> + +<p>Oraz:</p> + +<pre class="brush: js">var obj = {}; +</pre> + +<p>These are semantically equivalent; the second is called object literal syntax and is more convenient. This syntax is also the core of JSON format and should be preferred at all times.</p> + +<p>Semantycznie obie wersje są równe; druga, nazywana jest literalną składnią obiektu, jest wygodniejsza. Ta składnia jest dodatkowo kluczowym formatem JSON i powinna być preferowana w użyciu.</p> + +<p>Literalna składnia może być użyta do zainicjowania obiektu w całości:</p> + +<pre class="brush: js">var auto = { + marka: 'Ford', + model: 'Fiesta', + detale: { + kolor: 'grafitowy', + konieMechaniczne: 96 + } +}; +</pre> + +<p>Dostęp do atrybutu może być ze sobą połączony:</p> + +<pre class="brush: js">obj.detale.kolor; // grafitowy +obj['detale']['konieMechaniczne']; // 96 +</pre> + +<p>The following example creates an object prototype, <code>Person</code> and an instance of that prototype, <code>you</code>.</p> + +<p>Poniższy przykład tworzy prototyp obiektu <code>Person</code> i jego instancję, <code>marek</code>.</p> + +<pre class="brush: js">function Person(imie, wiek) { + this.imie = imie; + this.wiek = wiek; +} + +// Definiowanie obiektu +var marek = new Person('Marek', 24); +// Stworzyliśmy nową osobę o imieniu 'Marek' i wieku 24 lat. + +</pre> + +<p><strong>Once created</strong>, an object's properties can again be accessed in one of two ways:</p> + +<p>Do właściwości stworzonego obiektu można uzyskać dostep na dwa sposoby:</p> + +<pre class="brush: js">// notacja kropkowa ( <code>dot notation )</code> +obj.name = 'Simon'; +var name = obj.name; +</pre> + +<p>oraz...</p> + +<pre class="brush: js">// notacją nawiasową ( bracket notation ) +obj['name'] = 'Simon'; +var name = obj['name']; +// zmienna może być użyta do zdefiniowania wartości klucza +var user = prompt('what is your key?') +obj[user] = prompt('what is its value?') +</pre> + +<p>Te notacje także są semantycznie jednakowe. Druga metoda ma tę zaletę, że nazwa własności podawana jest jako string, dzięki czemu obliczana jest w czasie wykonywania. Jednak użycie tej metody zapobiega zastosowaniu niektórych mechanizmów JavaScript i procesów minifikacji. Może też być używany do ustawiania i pobierania własności z nazwami wykorzystującymi <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords">słowa zastrzeżone</a>: </p> + +<pre class="brush: js">obj.for = 'Simon'; // Syntax error, ponieważ 'for' jest zastrzeżone +obj['for'] = 'Simon'; // kod działa +</pre> + +<div class="note"> +<p>Począwszy od ECMAScript 5, słowa zastrzeżone mogą być używane jako nazwy własności obiektów "w locie". Oznacza to, że nie muszą być zamknięte w cudzysłów podczas definiowania obiektu notacją literałową. Zobacz <a href="http://es5.github.io/#x7.6.1">specyfikację ES5</a>.</p> +</div> + +<p>For more on objects and prototypes see <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype">Object.prototype</a>. For an explanation of object prototypes and the object prototype chains see <a href="/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">Inheritance and the prototype chain</a>.</p> + +<p>Po więcej informacji na temat obiektów i prototypów zobacz <a href="pl/docs/Web/JavaScript/Referencje/Obiekty/Object/prototype">Object.prototype</a>. Wyjaśnienie prototypów obiektów i łańcuch prototypów zobacz <a href="/pl/docs/Web/JavaScript/dziedziczenie_lancuch_prototypow">dziedziczenie i łańcuch prototypów</a>.</p> + +<h2 id="Tablice">Tablice</h2> + +<p>Tablice w JavaScript są specialnym typem obiektu. Działają bardzo podobnie do zwykłych obiektów, jednak posiadają jedną magiczną właściwość <code>'length'</code>. Jest ona zawsze o jeden więcej niż najwyższy index w tablicy.</p> + +<p>Poniżej jeden z sposób tworzenia tablcy:</p> + +<pre class="brush: js">var a = new Array(); +a[0] = 'pies'; +a[1] = 'kot'; +a[2] = 'hen'; +a.length; // 3 +</pre> + +<p><span class="tlid-translation translation" lang="pl"><span title="">Bardziej dogodną notacją jest użycie literału tablicy:</span></span></p> + +<pre class="brush: js">var a = ['dog', 'cat', 'hen']; +a.length; // 3 +</pre> + +<p><span class="tlid-translation translation" lang="pl"><span title="">Zauważ, że</span></span> <code>array.length</code> <span class="tlid-translation translation" lang="pl"><span title="">niekoniecznie jest liczbą elementów w tablicy.</span></span> <span class="tlid-translation translation" lang="pl"><span title="">Rozważ następujący zapis:</span></span></p> + +<pre class="brush: js">var a = ['dog', 'cat', 'hen']; +a[100] = 'fox'; +a.length; // 101 +</pre> + +<p><span class="tlid-translation translation" lang="pl"><span title="">Pamiętaj - długość tablicy jest o jeden większa niż najwyższy indeks.</span></span></p> + +<p>If you query a non-existent array index, you'll get a value of <code>undefined</code> in return:</p> + +<pre class="brush: js">typeof a[90]; // undefined +</pre> + +<p>If you take the above about <code>[]</code> and <code>length</code> into account, you can iterate over an array using the following <code>for</code> loop:</p> + +<pre class="brush: js">for (var i = 0; i < a.length; i++) { + // Do something with a[i] +} +</pre> + +<p>ECMAScript introduced the more concise <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...of"><code>for</code>...<code>of</code></a> loop for iterable objects such as arrays:</p> + +<pre class="brush:js">for (const currentValue of a) { + // Do something with currentValue +}</pre> + +<p>You could also iterate over an array using a <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...in" title="/en/JavaScript/Reference/Statements/for...in"><code>for</code>...<code>in</code></a> loop, however this does not iterate over the array elements, but the array indices. Furthermore, if someone added new properties to <code>Array.prototype</code>, they would also be iterated over by such a loop. Therefore this loop type is not recommended for arrays.</p> + +<p>Another way of iterating over an array that was added with ECMAScript 5 is <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach">forEach()</a></code>:</p> + +<pre class="brush: js">['dog', 'cat', 'hen'].forEach(function(currentValue, index, array) { + // Do something with currentValue or array[index] +}); +</pre> + +<p>If you want to append an item to an array simply do it like this:</p> + +<pre class="brush: js">a.push(item);</pre> + +<p>Arrays come with a number of methods. See also the <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">full documentation for array methods</a>.</p> + +<table> + <thead> + <tr> + <th scope="col">Method name</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>a.toString()</code></td> + <td>Returns a string with the <code>toString()</code> of each element separated by commas.</td> + </tr> + <tr> + <td><code>a.toLocaleString()</code></td> + <td>Returns a string with the <code>toLocaleString()</code> of each element separated by commas.</td> + </tr> + <tr> + <td><code>a.concat(item1[, item2[, ...[, itemN]]])</code></td> + <td>Returns a new array with the items added on to it.</td> + </tr> + <tr> + <td><code>a.join(sep)</code></td> + <td>Converts the array to a string — with values delimited by the <code>sep</code> param</td> + </tr> + <tr> + <td><code>a.pop()</code></td> + <td>Removes and returns the last item.</td> + </tr> + <tr> + <td><code>a.push(item1, ..., itemN)</code></td> + <td>Appends items to the end of the array.</td> + </tr> + <tr> + <td><code>a.reverse()</code></td> + <td>Reverses the array.</td> + </tr> + <tr> + <td><code>a.shift()</code></td> + <td>Removes and returns the first item.</td> + </tr> + <tr> + <td><code>a.slice(start[, end])</code></td> + <td>Returns a sub-array.</td> + </tr> + <tr> + <td><code>a.sort([cmpfn])</code></td> + <td>Takes an optional comparison function.</td> + </tr> + <tr> + <td><code>a.splice(start, delcount[, item1[, ...[, itemN]]])</code></td> + <td>Lets you modify an array by deleting a section and replacing it with more items.</td> + </tr> + <tr> + <td><code>a.unshift(item1[, item2[, ...[, itemN]]])</code></td> + <td>Prepends items to the start of the array.</td> + </tr> + </tbody> +</table> + +<h2 id="Functions">Functions</h2> + +<p>Along with objects, functions are the core component in understanding JavaScript. The most basic function couldn't be much simpler:</p> + +<pre class="brush: js">function add(x, y) { + var total = x + y; + return total; +} +</pre> + +<p>This demonstrates a basic function. A JavaScript function can take 0 or more named parameters. The function body can contain as many statements as you like and can declare its own variables which are local to that function. The <code>return</code> statement can be used to return a value at any time, terminating the function. If no return statement is used (or an empty return with no value), JavaScript returns <code>undefined</code>.</p> + +<p>The named parameters turn out to be more like guidelines than anything else. You can call a function without passing the parameters it expects, in which case they will be set to <code>undefined</code>.</p> + +<pre class="brush: js">add(); // NaN +// You can't perform addition on undefined +</pre> + +<p>You can also pass in more arguments than the function is expecting:</p> + +<pre class="brush: js">add(2, 3, 4); // 5 +// added the first two; 4 was ignored +</pre> + +<p>That may seem a little silly, but functions have access to an additional variable inside their body called <a href="/en-US/docs/Web/JavaScript/Reference/Functions/arguments" title="/en/JavaScript/Reference/Functions_and_function_scope/arguments"><code>arguments</code></a>, which is an array-like object holding all of the values passed to the function. Let's re-write the add function to take as many values as we want:</p> + +<pre class="brush: js">function add() { + var sum = 0; + for (var i = 0, j = arguments.length; i < j; i++) { + sum += arguments[i]; + } + return sum; +} + +add(2, 3, 4, 5); // 14 +</pre> + +<p>That's really not any more useful than writing <code>2 + 3 + 4 + 5</code> though. Let's create an averaging function:</p> + +<pre class="brush: js">function avg() { + var sum = 0; + for (var i = 0, j = arguments.length; i < j; i++) { + sum += arguments[i]; + } + return sum / arguments.length; +} + +avg(2, 3, 4, 5); // 3.5 +</pre> + +<p>This is pretty useful, but it does seem a little verbose. To reduce this code a bit more we can look at substituting the use of the arguments array through <a href="/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">Rest parameter syntax</a>. In this way, we can pass in any number of arguments into the function while keeping our code minimal. The <strong>rest parameter operator</strong> is used in function parameter lists with the format: <strong>...variable</strong> and it will include within that variable the entire list of uncaptured arguments that the function was called with. We will also replace the <strong>for</strong> loop with a <strong>for...of</strong> loop to return the values within our variable.</p> + +<pre class="brush: js">function avg(...args) { + var sum = 0; + for (let value of args) { + sum += value; + } + return sum / args.length; +} + +avg(2, 3, 4, 5); // 3.5 +</pre> + +<div class="note">In the above code, the variable <strong>args</strong> holds all the values that were passed into the function.<br> +<br> +It is important to note that wherever the rest parameter operator is placed in a function declaration it will store all arguments <em>after</em> its declaration, but not before. <em>i.e. function</em> <em>avg(</em><strong>firstValue, </strong><em>...args)</em><strong> </strong>will store the first value passed into the function in the <strong>firstValue </strong>variable and the remaining arguments in <strong>args</strong>. That's another useful language feature but it does lead us to a new problem. The <code>avg()</code> function takes a comma-separated list of arguments — but what if you want to find the average of an array? You could just rewrite the function as follows:</div> + +<pre class="brush: js">function avgArray(arr) { + var sum = 0; + for (var i = 0, j = arr.length; i < j; i++) { + sum += arr[i]; + } + return sum / arr.length; +} + +avgArray([2, 3, 4, 5]); // 3.5 +</pre> + +<p>But it would be nice to be able to reuse the function that we've already created. Luckily, JavaScript lets you call a function with an arbitrary array of arguments, using the {{jsxref("Function.apply", "apply()")}} method of any function object.</p> + +<pre class="brush: js">avg.apply(null, [2, 3, 4, 5]); // 3.5 +</pre> + +<p>The second argument to <code>apply()</code> is the array to use as arguments; the first will be discussed later on. This emphasizes the fact that functions are objects too.</p> + +<div class="note"> +<p>You can achieve the same result using the <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator">spread operator</a> in the function call.</p> + +<p>For instance: <code>avg(...numbers)</code></p> +</div> + +<p>JavaScript lets you create anonymous functions.</p> + +<pre class="brush: js">var avg = function() { + var sum = 0; + for (var i = 0, j = arguments.length; i < j; i++) { + sum += arguments[i]; + } + return sum / arguments.length; +}; +</pre> + +<p>This is semantically equivalent to the <code>function avg()</code> form. It's extremely powerful, as it lets you put a full function definition anywhere that you would normally put an expression. This enables all sorts of clever tricks. Here's a way of "hiding" some local variables — like block scope in C:</p> + +<pre class="brush: js">var a = 1; +var b = 2; + +(function() { + var b = 3; + a += b; +})(); + +a; // 4 +b; // 2 +</pre> + +<p>JavaScript allows you to call functions recursively. This is particularly useful for dealing with tree structures, such as those found in the browser DOM.</p> + +<pre class="brush: js">function countChars(elm) { + if (elm.nodeType == 3) { // TEXT_NODE + return elm.nodeValue.length; + } + var count = 0; + for (var i = 0, child; child = elm.childNodes[i]; i++) { + count += countChars(child); + } + return count; +} +</pre> + +<p>This highlights a potential problem with anonymous functions: how do you call them recursively if they don't have a name? JavaScript lets you name function expressions for this. You can use named IIFEs (Immediately Invoked Function Expressions) as shown below:</p> + +<pre class="brush: js">var charsInBody = (function counter(elm) { + if (elm.nodeType == 3) { // TEXT_NODE + return elm.nodeValue.length; + } + var count = 0; + for (var i = 0, child; child = elm.childNodes[i]; i++) { + count += counter(child); + } + return count; +})(document.body); +</pre> + +<p>The name provided to a function expression as above is only available to the function's own scope. This allows more optimizations to be done by the engine and results in more readable code. The name also shows up in the debugger and some stack traces, which can save you time when debugging.</p> + +<p>Note that JavaScript functions are themselves objects — like everything else in JavaScript — and you can add or change properties on them just like we've seen earlier in the Objects section.</p> + +<h2 id="Custom_objects">Custom objects</h2> + +<div class="note">For a more detailed discussion of object-oriented programming in JavaScript, see <a href="/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript">Introduction to Object-Oriented JavaScript</a>.</div> + +<p>In classic Object Oriented Programming, objects are collections of data and methods that operate on that data. JavaScript is a prototype-based language that contains no class statement, as you'd find in C++ or Java (this is sometimes confusing for programmers accustomed to languages with a class statement). Instead, JavaScript uses functions as classes. Let's consider a person object with first and last name fields. There are two ways in which the name might be displayed: as "first last" or as "last, first". Using the functions and objects that we've discussed previously, we could display the data like this:</p> + +<pre class="example-bad brush: js">function makePerson(first, last) { + return { + first: first, + last: last + }; +} +function personFullName(person) { + return person.first + ' ' + person.last; +} +function personFullNameReversed(person) { + return person.last + ', ' + person.first; +} + +s = makePerson('Simon', 'Willison'); +personFullName(s); // "Simon Willison" +personFullNameReversed(s); // "Willison, Simon" +</pre> + +<p>This works, but it's pretty ugly. You end up with dozens of functions in your global namespace. What we really need is a way to attach a function to an object. Since functions are objects, this is easy:</p> + +<pre class="brush: js">function makePerson(first, last) { + return { + first: first, + last: last, + fullName: function() { + return this.first + ' ' + this.last; + }, + fullNameReversed: function() { + return this.last + ', ' + this.first; + } + }; +} + +s = makePerson('Simon', 'Willison'); +s.fullName(); // "Simon Willison" +s.fullNameReversed(); // "Willison, Simon" +</pre> + +<p>There's something here we haven't seen before: the <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/this" title="/en/JavaScript/Reference/Operators/this">this</a></code> keyword. Used inside a function, <code>this</code> refers to the current object. What that actually means is specified by the way in which you called that function. If you called it using <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Accessing_properties" title="/en/JavaScript/Reference/Operators/Member_Operators">dot notation or bracket notation</a> on an object, that object becomes <code>this</code>. If dot notation wasn't used for the call, <code>this</code> refers to the global object.</p> + +<p>Note that <code>this</code> is a frequent cause of mistakes. For example:</p> + +<pre class="brush: js">s = makePerson('Simon', 'Willison'); +var fullName = s.fullName; +fullName(); // undefined undefined +</pre> + +<p>When we call <code>fullName()</code> alone, without using <code>s.fullName()</code>, <code>this</code> is bound to the global object. Since there are no global variables called <code>first</code> or <code>last</code> we get <code>undefined</code> for each one.</p> + +<p>We can take advantage of the <code>this</code> keyword to improve our <code>makePerson</code> function:</p> + +<pre class="brush: js">function Person(first, last) { + this.first = first; + this.last = last; + this.fullName = function() { + return this.first + ' ' + this.last; + }; + this.fullNameReversed = function() { + return this.last + ', ' + this.first; + }; +} +var s = new Person('Simon', 'Willison'); +</pre> + +<p>We have introduced another keyword: <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/new" title="/en/JavaScript/Reference/Operators/new">new</a></code>. <code>new</code> is strongly related to <code>this</code>. It creates a brand new empty object, and then calls the function specified, with <code>this</code> set to that new object. Notice though that the function specified with <code>this</code> does not return a value but merely modifies the <code>this</code> object. It's <code>new</code> that returns the <code>this</code> object to the calling site. Functions that are designed to be called by <code>new</code> are called constructor functions. Common practice is to capitalize these functions as a reminder to call them with <code>new</code>.</p> + +<p>The improved function still has the same pitfall with calling <code>fullName()</code> alone.</p> + +<p>Our person objects are getting better, but there are still some ugly edges to them. Every time we create a person object we are creating two brand new function objects within it — wouldn't it be better if this code was shared?</p> + +<pre class="brush: js">function personFullName() { + return this.first + ' ' + this.last; +} +function personFullNameReversed() { + return this.last + ', ' + this.first; +} +function Person(first, last) { + this.first = first; + this.last = last; + this.fullName = personFullName; + this.fullNameReversed = personFullNameReversed; +} +</pre> + +<p>That's better: we are creating the method functions only once, and assigning references to them inside the constructor. Can we do any better than that? The answer is yes:</p> + +<pre class="brush: js">function Person(first, last) { + this.first = first; + this.last = last; +} +Person.prototype.fullName = function() { + return this.first + ' ' + this.last; +}; +Person.prototype.fullNameReversed = function() { + return this.last + ', ' + this.first; +}; +</pre> + +<p><code>Person.prototype</code> is an object shared by all instances of <code>Person</code>. It forms part of a lookup chain (that has a special name, "prototype chain"): any time you attempt to access a property of <code>Person</code> that isn't set, JavaScript will check <code>Person.prototype</code> to see if that property exists there instead. As a result, anything assigned to <code>Person.prototype</code> becomes available to all instances of that constructor via the <code>this</code> object.</p> + +<p>This is an incredibly powerful tool. JavaScript lets you modify something's prototype at any time in your program, which means you can add extra methods to existing objects at runtime:</p> + +<pre class="brush: js">s = new Person('Simon', 'Willison'); +s.firstNameCaps(); // TypeError on line 1: s.firstNameCaps is not a function + +Person.prototype.firstNameCaps = function() { + return this.first.toUpperCase(); +}; +s.firstNameCaps(); // "SIMON" +</pre> + +<p>Interestingly, you can also add things to the prototype of built-in JavaScript objects. Let's add a method to <code>String</code> that returns that string in reverse:</p> + +<pre class="brush: js">var s = 'Simon'; +s.reversed(); // TypeError on line 1: s.reversed is not a function + +String.prototype.reversed = function() { + var r = ''; + for (var i = this.length - 1; i >= 0; i--) { + r += this[i]; + } + return r; +}; + +s.reversed(); // nomiS +</pre> + +<p>Our new method even works on string literals!</p> + +<pre class="brush: js">'This can now be reversed'.reversed(); // desrever eb won nac sihT +</pre> + +<p>As mentioned before, the prototype forms part of a chain. The root of that chain is <code>Object.prototype</code>, whose methods include <code>toString()</code> — it is this method that is called when you try to represent an object as a string. This is useful for debugging our <code>Person</code> objects:</p> + +<pre class="brush: js">var s = new Person('Simon', 'Willison'); +s.toString(); // [object Object] + +Person.prototype.toString = function() { + return '<Person: ' + this.fullName() + '>'; +} + +s.toString(); // "<Person: Simon Willison>" +</pre> + +<p>Remember how <code>avg.apply()</code> had a null first argument? We can revisit that now. The first argument to <code>apply()</code> is the object that should be treated as '<code>this</code>'. For example, here's a trivial implementation of <code>new</code>:</p> + +<pre class="brush: js">function trivialNew(constructor, ...args) { + var o = {}; // Create an object + constructor.apply(o, args); + return o; +} +</pre> + +<p>This isn't an exact replica of <code>new</code> as it doesn't set up the prototype chain (it would be difficult to illustrate). This is not something you use very often, but it's useful to know about. In this snippet, <code>...args</code> (including the ellipsis) is called the "<a href="/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest arguments</a>" — as the name implies, this contains the rest of the arguments.</p> + +<p>Calling</p> + +<pre class="brush: js">var bill = trivialNew(Person, 'William', 'Orange');</pre> + +<p>is therefore almost equivalent to</p> + +<pre class="brush: js">var bill = new Person('William', 'Orange');</pre> + +<p><code>apply()</code> has a sister function named <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call" title="/en/JavaScript/Reference/Global_Objects/Function/call"><code>call</code></a>, which again lets you set <code>this</code> but takes an expanded argument list as opposed to an array.</p> + +<pre class="brush: js">function lastNameCaps() { + return this.last.toUpperCase(); +} +var s = new Person('Simon', 'Willison'); +lastNameCaps.call(s); +// Is the same as: +s.lastNameCaps = lastNameCaps; +s.lastNameCaps(); // WILLISON +</pre> + +<h3 id="Inner_functions">Inner functions</h3> + +<p>JavaScript function declarations are allowed inside other functions. We've seen this once before, with an earlier <code>makePerson()</code> function. An important detail of nested functions in JavaScript is that they can access variables in their parent function's scope:</p> + +<pre class="brush: js">function parentFunc() { + var a = 1; + + function nestedFunc() { + var b = 4; // parentFunc can't use this + return a + b; + } + return nestedFunc(); // 5 +} +</pre> + +<p>This provides a great deal of utility in writing more maintainable code. If a function relies on one or two other functions that are not useful to any other part of your code, you can nest those utility functions inside the function that will be called from elsewhere. This keeps the number of functions that are in the global scope down, which is always a good thing.</p> + +<p>This is also a great counter to the lure of global variables. When writing complex code it is often tempting to use global variables to share values between multiple functions — which leads to code that is hard to maintain. Nested functions can share variables in their parent, so you can use that mechanism to couple functions together when it makes sense without polluting your global namespace — "local globals" if you like. This technique should be used with caution, but it's a useful ability to have.</p> + +<h2 id="Closures">Closures</h2> + +<p>This leads us to one of the most powerful abstractions that JavaScript has to offer — but also the most potentially confusing. What does this do?</p> + +<pre class="brush: js">function makeAdder(a) { + return function(b) { + return a + b; + }; +} +var x = makeAdder(5); +var y = makeAdder(20); +x(6); // ? +y(7); // ? +</pre> + +<p>The name of the <code>makeAdder()</code> function should give it away: it creates new 'adder' functions, each of which, when called with one argument, adds it to the argument that it was created with.</p> + +<p>What's happening here is pretty much the same as was happening with the inner functions earlier on: a function defined inside another function has access to the outer function's variables. The only difference here is that the outer function has returned, and hence common sense would seem to dictate that its local variables no longer exist. But they <em>do</em> still exist — otherwise, the adder functions would be unable to work. What's more, there are two different "copies" of <code>makeAdder()</code>'s local variables — one in which <code>a</code> is 5 and the other one where <code>a</code> is 20. So the result of that function calls is as follows:</p> + +<pre class="brush: js">x(6); // returns 11 +y(7); // returns 27 +</pre> + +<p>Here's what's actually happening. Whenever JavaScript executes a function, a 'scope' object is created to hold the local variables created within that function. It is initialized with any variables passed in as function parameters. This is similar to the global object that all global variables and functions live in, but with a couple of important differences: firstly, a brand new scope object is created every time a function starts executing, and secondly, unlike the global object (which is accessible as <code>this</code> and in browsers as <code>window</code>) these scope objects cannot be directly accessed from your JavaScript code. There is no mechanism for iterating over the properties of the current scope object, for example.</p> + +<p>So when <code>makeAdder()</code> is called, a scope object is created with one property: <code>a</code>, which is the argument passed to the <code>makeAdder()</code> function. <code>makeAdder()</code> then returns a newly created function. Normally JavaScript's garbage collector would clean up the scope object created for <code>makeAdder()</code> at this point, but the returned function maintains a reference back to that scope object. As a result, the scope object will not be garbage-collected until there are no more references to the function object that <code>makeAdder()</code> returned.</p> + +<p>Scope objects form a chain called the scope chain, similar to the prototype chain used by JavaScript's object system.</p> + +<p>A <strong>closure</strong> is the combination of a function and the scope object in which it was created. Closures let you save state — as such, they can often be used in place of objects. You can find <a href="http://stackoverflow.com/questions/111102/how-do-javascript-closures-work">several excellent introductions to closures</a>.</p> |