diff options
Diffstat (limited to 'files/hu/web/javascript/a_re-introduction_to_javascript/index.html')
| -rw-r--r-- | files/hu/web/javascript/a_re-introduction_to_javascript/index.html | 948 |
1 files changed, 948 insertions, 0 deletions
diff --git a/files/hu/web/javascript/a_re-introduction_to_javascript/index.html b/files/hu/web/javascript/a_re-introduction_to_javascript/index.html new file mode 100644 index 0000000000..89192fcbf4 --- /dev/null +++ b/files/hu/web/javascript/a_re-introduction_to_javascript/index.html @@ -0,0 +1,948 @@ +--- +title: A JavaScript újbóli bemutatása +slug: Web/JavaScript/a_javascript_ujboli_bemutatasa +translation_of: Web/JavaScript/A_re-introduction_to_JavaScript +--- +<div>{{jsSidebar}}</div> + +<p>Hogy miért újboli bemutatása? Azért, mert a {{Glossary("JavaScript")}} <a href="http://javascript.crockford.com/javascript.html">a világ legfélreértetteb programozási nyelveként ismert</a>. Gyakran lebecsülik mint egyfajta játékszert, de az egyszerűsége mellett, erőteljes nyelvi eszközökkel rendelkezik. A JavaScript -et manapság rengeteg fontos alkalmazásban használják, ami azt mutatja, hogy ennek a technológiának a tudása minden web - és mobilalkalmazás fejlesztőnek egy fontos tulajdonsága.</p> + +<p>Érdemes a nyelv történetének áttekintésével kezdeni. A JavaScript -et Brendan Eich tervezte 1995 -ben, aki a Netscape - nél volt mérnök. A JavaScript először a Netscape 2 -vel lett kiadva 1996 elején. A nyelvet eredetileg LiveScript - nek nevezték, de egy szerencsétlen marketingdöntés miatt átnevezték, amivel a Sun Microsystems nyelvének, a Java -nak a népszerűségét akarták a hasznukra fordítani, noha a két nyelvben kevés közös dolog volt. Ez máig az összezavarodottság egyik forrása.</p> + +<p>Néhány hónappal később Microsoft bemutatta a JScript - et az Internet Explorer 3 kiadásakor. Ez egy nagymértékben JavaScript kompatibilis nyelv volt. Néhány hónap elteltével a Netscape átadta a JavaScript - et az <a class="external" href="http://www.ecma-international.org/">Ecma International</a> - nek, és ez az európai szabványosító szervezet még ebben az évben nyilvánosságra hozta az {{Glossary("ECMAScript")}} első verzióját . A szabvány 1999 - ben jelentős frissitést kapott a <a class="external" href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript edition 3</a> -al, és azóta nagyon stabil. A szabvány negyedik kiadása a politikai nézeteltérések, és a nyelv növekvő komplexitása miatt megszűnt. A negyedik verzió sok eleme képezte alapját a szabvány ötödik, és hatodik kiadásának, amiket 2009. decemberében, valamint 2015 Júniusában adtak ki.</p> + +<div class="note"> +<p>Az ismertség miatt innentől az ECMAScript helyett a JavaScript megnevezést használjuk.</p> +</div> + +<p>A legtöbb programozásinyelvtől eltérően, a JavaScript - ben nincs terv a standard ki - és bemenetre. A JavaScript arra lett tervezve, hogy egy szkriptként fusson egy hoszt környezetben, így ezen környezet mechanizmusainak feladata a külvilággal való kapcsolat biztosítása. A leggyakrabban erre használt hoszt környezet a böngésző, ám sok más alkalmazásban is található értelmező, mint a <a href="http://nodejs.org/">Node.js</a>, NoSQL adatbázisok mint a nyílt forrású <a href="http://couchdb.apache.org/">Apache CouchDB</a>, beágyazott rendszerek, teljes asztali környezetek mint a <a href="http://www.gnome.org/">GNOME</a> (A GNU/Linux operációs rendszerek számára az egyik a legnépszerűbb grafikus felhasználói interfészek közül), és még sok más.</p> + +<h2 id="Áttekintés">Áttekintés</h2> + +<p>A JavaScript multi-paradigmájú nyelv, típusokkal, operátorokkal, beépített standard objektumokkal, és metódusokkal. A szintaxisa a Java és a C nyelvekel alapul — sok struktúra lett ezekből a nyelvekből a JavaScript - be átvéve. A JavaScript osztályok helyett prototípus objektumokkal támogatja az objektumorintáltságot (többet erről <a href="/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain" title="prototypical inheritance">prototypical inheritance</a> és ES2015 <a href="/en-US/docs/Web/JavaScript/Reference/Classes">classes</a>). A JavaScript a funkcionális programozást is támogatja — a függvények objektumok, lehetővé teszik a végrehajtható kód tárolását, és a függvények, mint minden objektum, továbbadhatóak.</p> + +<p>Kezdjük a nyelv éíptőköveinek szemlélésével. A JavaScript programok értékeket manipulálnak, és minden értéknek van egy meghatározott típusa. JavaScript típusok a:</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>... ó, és {{jsxref("undefined")}} és a {{jsxref("null")}}, amik egy kissé speciálisak, az {{jsxref("Array")}}, ami egy különleges fajtájú objektum, a {{jsxref("Date")}} és a {{jsxref("RegExp")}}, amiket csak úgy kapsz. Ha pontosak akarunk lenni, a függvények is egy fajta objektumok. Tehát a típusok felsorolása inkább így néz ki:</p> + +<ul> + <li>{{jsxref("Number")}}</li> + <li>{{jsxref("String")}}</li> + <li>{{jsxref("Boolean")}}</li> + <li>{{jsxref("Symbol")}} (Az ES2015 - ben új)</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>és van még néhány előre definiált {{jsxref("Error")}} típus. Az egyszerűség kedvéért most csak az első felsorolásra korlátozódunk.</p> + +<h2 id="Számok">Számok</h2> + +<p>A számok a JavaScript - ben a specifikáció szerint "dupla precíz 64-bit formátumú IEEE 754 értékek". Ennek van néhány érdekes következménye. JavaScript - ben nincs olyasmihez hasonlítható, mint az integer, ami miatt óvatosan kell az aritmetikával bánni, ha a matematikát úgy alkalmazzuk mint a C -ben, vagy Java -ban.</p> + +<p>Figyelj oda olyan dolgokra, mint:</p> + +<pre class="brush: js">0.1 + 0.2 == 0.30000000000000004; +</pre> + +<p>A gyakolatban az integer értékek 32-Bit -es integerként vannak kezelve, és egyes implemetációk még úgy is tárolják őket, amíg egy olyan utasítást kell végrehajtsanak ami egy számra, de nem egy integerre érvényes. Ez például a bitműveleteknél lehet fontos.</p> + +<p>Támogatottak az alapértelmezett <a href="/en-US/docs/Web/JavaScript/Reference/Operators#Arithmetic_operators">aritmetikai operátorok</a>, beleértve az összeadást, kivonást, modulo (maradék), és így tovább. Ezenkívül létezik még egy {{jsxref("Math")}} objektum, ami olyan matematikai funkciókat nyújt, amik fent még nem lettek említve:</p> + +<pre class="brush: js">Math.sin(3.5); +var atmero = 2 * Math.PI * r; +</pre> + +<p>Egy stringet a beépített {{jsxref("Global_Objects/parseInt", "parseInt()")}} funkcióval integerré lehet konvertálni. A funkció megkapja a használt számrendszer alapját, ez a második opcionális paraméter, ami mindig meg kell legyen adva:</p> + +<pre class="brush: js">parseInt('123', 10); // 123 +parseInt('010', 10); // 10 +</pre> + +<p>Régebbi böngészőkön a 0 -val kezdődő sztringek oktális számként értelmeződnek (8 -as alapú), de ez 2013 óta már nincs így. Ha nem vagyunk biztosak a string formátumban, a régebbi böngészők meglepő ereményhez vezethetnek:</p> + +<pre class="brush: js">parseInt('010'); // 8 +parseInt('0x10'); // 16 +</pre> + +<p>Itt látható, hogy a {{jsxref("Global_Objects/parseInt", "parseInt()")}} függvény a 0 előtag miatt az első stringet oktális számként, a második stringet a "0x" előtag miatt hexadecimális számként értelmezi. A <em>hexadecimális szemlélet még mindig megengedett,</em> csak az oktális lett eltávolítva.</p> + +<p>Ha egy bináris számot szeretnél integerré alakítani, egyszerűen a bázist kell megváltoztatni 2 -re.</p> + +<pre class="brush: js">parseInt('11', 2); // 3 +</pre> + +<p>Ezzel a módszerrel lebegőpontos számokat is konvertálhatunk a {{jsxref("Global_Objects/parseFloat", "parseFloat()")}} függvény segítségével. A {{jsxref("Global_Objects/parseInt", "parseInt()")}} függvénnyel ellentétben, a <code>parseFloat()</code> mindig 10 -es bázist használ.</p> + +<p>Az unáris (egy operandusú) <code>+</code> operátor is használható számok konvertálására:</p> + +<pre class="brush: js">+ '42'; // 42 ++ '010'; // 10 ++ '0x10'; // 16 +</pre> + +<p>Ha egy string nem tartalmaz numerikus értékeet, egy speciális érték a {{jsxref("NaN")}} (A "Not a Number" rövidítése) adódik vissza.</p> + +<pre class="brush: js">parseInt('hello', 10); // NaN +</pre> + +<p>A <code>NaN</code> veszélyes: Ha egy matematikai művelet egyik operandusaként használjuk, az eredmény is <code>NaN</code> lesz:</p> + +<pre class="brush: js">NaN + 5; // NaN +</pre> + +<p>A beépített {{jsxref("Global_Objects/isNaN", "isNaN()")}} függvény segítségével lehet megállapítani, hogy egy változó értéke <code>NaN</code> - e:</p> + +<pre class="brush: js">isNaN(NaN); // true +</pre> + +<p>A JavaScript - ben vannak olyan speciális értékek is, mint az {{jsxref("Infinity")}} és a <code>-Infinity</code>:</p> + +<pre class="brush: js"> 1 / 0; // Infinity +-1 / 0; // -Infinity +</pre> + +<p>Az <code>Infinity</code>, <code>-Infinity</code> és <code>NaN</code> értékeket a beépített {{jsxref("Global_Objects/isFinite", "isFinite()")}} függvényekel lehet tesztelni:</p> + +<pre class="brush: js">isFinite(1 / 0); // false +isFinite(-Infinity); // false +isFinite(NaN); // false +</pre> + +<div class="note">A {{jsxref("Global_Objects/parseInt", "parseInt()")}} és a {{jsxref("Global_Objects/parseFloat", "parseFloat()")}} addig olvassák a stringet, amíg nem találnak egy olyan karaktert, ami a számrendszerben nem található, és csak az eddig beolvasott számokat adja vissza értékül. Az unáris "+" viszont egyszerűen <code>NaN</code> értéket ad vissza, ha a string egy nem érvényes karaktert tartalmaz. Próbáld meg értelmezni a konzolban a "10.2abc" stringet, hogy jobban megérthesd a köztük lévő különbségeket.</div> + +<h2 id="Karakterláncok">Karakterláncok</h2> + +<p>A stringek a JavaScript -ben <a href="/en-US/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Unicode">Unicode karakterek</a> sorozata. Ez mindenki számára örvendetes lehet, akik több nyelvű szoftvereken dolgoznak. Még pontosabban fogalmazva, a stringek UTF-16 kódegységek sorozata; mindegy egyes egység egy 16-bites számmal van reprezentálva. Minden Unicode karakter egy, vagy két kódegységből áll.</p> + +<p>Egyetlen karakter reprezentálásához egyszerűen egyetlen karaktert használunk.</p> + +<p>Egy string hosszát (kód egységekben), a <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length">length</a></code> property -vel (tulajdonság, az objektum tagváltozója) kapjuk meg:</p> + +<pre class="brush: js">'hello'.length; // 5 +</pre> + +<p>Ez az első találkozásunk egy JavaScript objektummal! Említettük már, hogy a stringeket úgy használhatjuk, mint az {{jsxref("Object", "objektumokat", "", 1)}} ? Vannak nekik {{jsxref("String", "metódusaik", "#Methods", 1)}} is, amiknek segítségével megváltoztathatjuk a stringet, és információkat kaphatunk róla:</p> + +<pre class="brush: js">'hello'.charAt(0); // "h" +'hello, world'.replace('world', 'mars'); // "hello, mars" +'hello'.toUpperCase(); // "HELLO" +</pre> + +<h2 id="Egyéb_típusok">Egyéb típusok</h2> + +<p>A JavaScript különbséget tesz a {{jsxref("null")}}, ami egy "nem értéket" reprezentál, (és csak a <code>null</code> kulcsszón keresztül érhető el), és az {{jsxref("undefined")}} között, ami egy <code>undefined</code> típus, és egy nem inicializált értéket jelez, tehát hogy még nem lett a változónak érték adva. A változókról még később szó lesz, de a JavaScript -ben lehet úgy változókat deklarálni, hogy nem rendelünk hozzá értéket. Ha így teszel, a változó típusa <code>undefined</code> lesz. Az <code>undefined</code> egy konstans.</p> + +<p>A JavaScript -nek van egy boolean típusa, <code>true</code> és <code>false</code> lehetséges értékkekkel (mindkettő ezek közül kulcsszó.) Minden érték boolean - é konvertálható a következő szabályok figyelembevételével:</p> + +<ol> + <li><code>false</code>, <code>0</code>, üres stringek (<code>""</code>), <code>NaN</code>, <code>null</code>, és <code>undefined</code> értékekből <code>false</code> lesz.</li> + <li>Minden más értékből <code>true</code> lesz.</li> +</ol> + +<p>A konverzió közvetlenül a <code>Boolean()</code> függvénnyel hajtható végre:</p> + +<pre class="brush: js">Boolean(''); // false +Boolean(234); // true +</pre> + +<p>Viszont ez alig szükséges, mivel a JavaScript automatikusan elvégzi a konverziót,ha boolean értéket vár, mint például az <code>if</code> utasítás esetén (lásd lentebb). Ezen ok miatt gyakran beszélünk "true értékekről" és "false értékekről," ami alatt azt értjük, hogy az értékek <code>true</code> vagy <code>false</code> lesznek, miután Boolean -é lettek átalakítva. Ezek az értékek másképpen "truthy" és "falsy".</p> + +<p>A Boolean műveletek mint például az <code>&&</code> (logikai <em>és</em>), <code>||</code> (logikai <em>vagy</em>), és <code>!</code> (logikai <em>nem</em>) támogatottak (lásd lentebb).</p> + +<h2 id="Változók">Változók</h2> + +<p>JavaScript-ben az új változókat három kulcsszóval lehet deklarálni: <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/let">let</a></code>, <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/const">const</a></code>, vagy <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/var" title="/en/JavaScript/Reference/Statements/var">var</a></code>.<br> + <br> + A <strong><code>let</code> </strong>kulcsszóval blokk szintű változókat lehet deklarálni. Az így deklarált változó abból a kód blokkból érhető el, ahol azt definiálták.</p> + +<pre class="brush: js">let a; +let name = 'Simon'; +</pre> + +<p>A következő példa a <code><strong>let</strong></code> kulcsszóval deklarált változó láthatóságát mutatja be.</p> + +<pre class="brush: js">// A myLetVariable itt *NEM* látható. + +for (let myLetVariable = 0; myLetVariable < 5; myLetVariable++) { + // A myLetVariable csak itt elérhető +} + +// A myLetVariable itt *NEM* látható. + +</pre> + +<p>A <strong><code>const</code> </strong>kulcsszóval olyan változó deklarálható, aminek az értéke nem változik meg. A változó abból a <em>kód blokkból</em> érhető el, amiben deklarálták.</p> + +<pre class="brush: js">const Pi = 3.14; // A Pi változó értékének megadása +Pi = 1; // kivételt fog dobni, mivel egy konstans értéke nem változtatható meg</pre> + +<p><br> + A <strong><code>var</code></strong> a leghasználatosabb deklaratív kulcsszó, nincsenek olyan korlátozásai mint a másik kettőnek. Ennek az az oka, hogy hagyományosan ez volt az egyetlen mód egy változó deklarálására a JavaScriptben. A <strong><code>var</code> </strong>kulcsszóval deklarált változó abban a <em>függvényben</em> érhető el, amiben azt deklarálták.</p> + +<pre class="brush: js">var a; +var name = 'Simon';</pre> + +<p>A következő példa a <code><strong>var</strong></code> kulcsszóval deklarált változó láthatóságát mutatja be.</p> + +<pre class="brush: js">// A myVarVariable itt látható + +for (var myVarVariable = 0; myVarVariable < 5; myVarVariable++) { + // A myVarVariable látható az egész függvényben +} + +// A myVarVariable itt is látható +</pre> + +<p>Ha egy olyan változót deklarálunk, amihez nem lett érték hozzárendelve, a típusa <code>undefined</code> lesz.</p> + +<p>Egy fontos különbség a JavaScript és más nyelvek között (pl. a Java), hogy a JavaScript-ben a blokkoknak nincsen érvényességi területük (scope), Csak a függvényeknek. Szóval, ha egy <code>var</code> kulcsszóval definiálunk változót (például egy <code>if</code> vezérlőszerkezeten belül), Akkor az az egész függvényben látható lesz. Azonban az ECMAScript 2015-ös verziójától, a <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/let">let</a></code> és <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/const">const</a></code> kulcsszóval deklarált változók, lehetővé teszik a scope-ok létrehozását.</p> + +<h2 id="Operátorok">Operátorok</h2> + +<p>A JavaScript's numerikus operátorai a <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code> és <code>%</code> ami a maradék operátor (<a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Remainder_%28%29">Ami nem ugyanaz, mint a modulo</a>.) Az értékadás az <code>=</code> használatával történik, és létezik összevont értékadás is mint a <code>+=</code> és a <code>-=</code>. Ezek a következőféleképp értelmezendőek:<br> + <code>x = x <em>operator</em> y</code>.</p> + +<pre class="brush: js">x += 5; +x = x + 5; +</pre> + +<p>A <code>++</code> és <code>--</code> operátorokat inkrementálásta and dekrementálásra lehet használni. Ezek használhatóak prefix és postfix operátorokként is.</p> + +<p>A <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Addition" title="/en/JavaScript/Reference/Operators/String_Operators"><code>+</code> operátor</a> stringek egyesítésére is :</p> + +<pre class="brush: js">'hello' + ' world'; // "hello world" +</pre> + +<p>Ha egy stringet és egy számot (vagy más értéket) összeadunk, először minden string-é konvertálódik. Ez néha problémák forrása:</p> + +<pre class="brush: js">'3' + 4 + 5; // "345" + 3 + 4 + '5'; // "75" +</pre> + +<p>Egy üres string hozzáadása egy értékhez jó módszer arra, hogy az értéket string-é konvertáljuk.</p> + +<p>A JavaScriptben <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators" title="/en/JavaScript/Reference/Operators/Comparison_Operators">Összehasonlításokat</a> a <code><</code>, <code>></code>, <code><=</code> és <code>>=</code> operátorok használatával lehet elvégezni. Ezek stringek és számok esetén használhatóak. Az egyenlőség egy kicsit bonyolultabb. Az <code>==</code> operátor típuskonverziót kényszerít ki, ami érdekes eredményekhez vezethet:</p> + +<pre class="brush: js">123 == '123'; // true +1 == true; // true +</pre> + +<p>A típuskonverzió elkerüléséhez használjuk a <code>===</code> (teljesen egyenlő) operátort:</p> + +<pre class="brush: js">123 === '123'; // false +1 === true; // false +</pre> + +<p>Léteznek <code>!=</code> és <code>!==</code> operátorok is.</p> + +<p>A JavaScript-ben vannak <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators" title="/en/JavaScript/Reference/Operators/Bitwise_Operators">bitszintű műveletek</a> is.</p> + +<h2 id="Vezérlő_szerkezetek">Vezérlő szerkezetek</h2> + +<p>A JavaScript hasonló a C nyelvcsalád nyelveihez hasonlóvezérlő szerkezetekkel rendelkezik. Feltételes utasítások az <code>if</code> és <code>else</code> kulcsszavakkal hozhatók létre. Ezek összeláncolhatóak:</p> + +<pre class="brush: js">var name = 'kittens'; +if (name == 'puppies') { + name += ' woof'; +} else if (name == 'kittens') { + name += ' meow'; +} else { + name += '!'; +} +name == 'kittens meow'; +</pre> + +<p>A JavaScript-ben vannak <code>while</code> és <code>do-while</code> ciklusok. Az egyszerű alkalmas egyszerű ciklusok létrehozására; a második olyan ciklusok létrehozására használatos, ahol biztosítani kívánjuk, hogy a ciklus tartalma (ciklusmag) legalább egyszer lefusson:</p> + +<pre class="brush: js">while (true) { + // végtelen ciklus! +} + +var input; +do { + input = get_input(); +} while (inputIsNotValid(input)); +</pre> + +<p>A JavaScript <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for"><code>for</code> ciklusa</a> ugyanaz mint a C-ben és Java-ban megszokott: A vezérlőinformációk egyetlen sorban megadhatóak.</p> + +<pre class="brush: js">for (var i = 0; i < 5; i++) { + // ötször fut le +} +</pre> + +<p>A JavaScript-ben van két másik népszerű for ciklus is:<br> + A <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...of"><code>for</code>...<code>of</code></a></p> + +<pre class="brush: js">for (let value of array) { + // value feldolgozása +} +</pre> + +<p>és a <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 property in object) { + // objektum tulajdonságának feldolgozása +} +</pre> + +<p>A <code>&&</code> és <code>||</code> operátorok a rövidzár logikát alkalmazzák, ami azt jelenti, hogy a második operandus végrehajtása az eslő operandustól függ. Ez hasznos null objektumok ellenőrzésére, mielőtt megpróbálnánk hozzáférni az attributúmaihoz:</p> + +<pre class="brush: js">var name = o && o.getName(); +</pre> + +<p>vagy értékek cachelésére (ha a falsy értékek érvénytelenek):</p> + +<pre class="brush: js">var name = cachedName || (cachedName = getName()); +</pre> + +<p>A JavaScript-ben van egy ternáris operátor, feltételek létrehozásához:</p> + +<pre class="brush: js">var allowed = (age > 18) ? 'yes' : 'no'; +</pre> + +<p>A <code>switch</code> többszörös elágazásakhoz használható egy string vagy egy szám tartalmától függően:</p> + +<pre class="brush: js">switch (action) { + case 'draw': + drawIt(); + break; + case 'eat': + eatIt(); + break; + default: + doNothing(); +} +</pre> + +<p>Ha nem adunk hozzá <code>break</code> utasítást, a vezérlés átlép a következő <code>case</code> ágra. Ezt ritka esetekben használják — ilyenkor megéri egy kommentet hozzáfűzni, hogy a későbbi hibakeresést megkönnyítse:</p> + +<pre class="brush: js">switch (a) { + case 1: // átlép a következőre + case 2: + eatIt(); + break; + default: + doNothing(); +} +</pre> + +<p>A <code>default</code> ág nem kötelező. Ha szeretnénk a switch részben, és az case részben is lehetnek utasítások; Az összehasonlítás a kettő között a <code>===</code> operátorral történik:</p> + +<pre class="brush: js">switch (1 + 3) { + case 2 + 2: + yay(); + break; + default: + sosemtortenikmeg(); +} +</pre> + +<h2 id="Objektumok">Objektumok</h2> + +<p>A JavaScript objektumok egyszerű név - érték párokból állnak. Ezek hasonlóak mint a:</p> + +<ul> + <li>Python Szótárak.</li> + <li>Perl és Ruby Hash-ek.</li> + <li>C és C++ Hash táblák.</li> + <li>Java HashMaps .</li> + <li>PHP asszociatív tömbök .</li> +</ul> + +<p>Az a tény, hogy ezt az adatstruktúrát olyan széles körben alkalmazzák, a sokoldalúságát bizonyítja. Mivel a JavaScriptben minden (a tiszta core típusok) egy objektum, úgy természetesen minden JavaScript program egy csomó keresési műveletet végez el a hash-táblákban. Jó hogy ezek ilyen gyorsak!</p> + +<p>A "név" rész az egy JavaScript string, az érték viszont bármilyen JavaScript érték lehet, beleértve más objektumokat is. Ez lehetővé teszi a tetszőlegesen összetett adatstruktúrák létrehozását.</p> + +<p>Egy üres objektum létrehozására két lehetőség van:</p> + +<pre class="brush: js">var obj = new Object(); +</pre> + +<p>és:</p> + +<pre class="brush: js">var obj = {}; +</pre> + +<p>Ezek szemantikailag egyformák; a másodikat object literal szintaxisnak hívják, és elterjedtebb. Ez a szintaxis a magja a JSON formátumnak is.</p> + +<p>Az Object literal szintaxis egy átfogó objektum inicializálására használható:</p> + +<pre class="brush: js">var obj = { + name: 'Carrot', + for: 'Max', // 'for' egy foglalt szó, használjunk '_for' -t helyette. + details: { + color: 'orange', + size: 12 + } +}; +</pre> + +<p>A tulajdonságok elérése összefűzhető:</p> + +<pre class="brush: js">obj.details.color; // orange +obj['details']['size']; // 12 +</pre> + +<p>A kövekező példa egy <code>Person</code> prototípust készít, és ezen prototípusnak egy <code>you</code> nevű példányát.</p> + +<pre class="brush: js">function Person(name, age) { + this.name = name; + this.age = age; +} + +// Define an object +var you = new Person('You', 24); +// We are creating a new person named "You" aged 24. + +</pre> + +<p><strong>Példányosítás után</strong>, egy objektum tulajdonságait két féle képpen lehet elérni:</p> + +<pre class="brush: js">// dot notation +obj.name = 'Simon'; +var name = obj.name; +</pre> + +<p>és...</p> + +<pre class="brush: js">// bracket notation +obj['name'] = 'Simon'; +var name = obj['name']; +// egy változó használható kulcs létrehozására +var user = prompt('what is your key?') +obj[user] = prompt('what is its value?') +</pre> + +<p>Ezek szemantikailag egyformák. A második módszer előnye, hogy a tulajdonság nevét stringként lehet megadni, ami azt jelenti, hogy futási időben dől el. Ám ez a módszer megakadályozza néhány JavaScript motor és minifier optimalizáció végrehajtását. Ez a módszer arra is alkalmazható, hogy olyan tulajdoságokat létrehozhassunk, és elérjünk amik <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords" title="/en/JavaScript/Reference/Reserved_Words">foglalt szavakat</a> használnak.</p> + +<pre class="brush: js">obj.for = 'Simon'; // Syntax error, mert a 'for' egy foglalt szó +obj['for'] = 'Simon'; // működik +</pre> + +<div class="note"> +<p>Az ECMAScript 5-től kezdve, a foglalt szavak is használhatóak az objektumliterálokban. ez azt jelenti, hogy nem kell "idézőjelek kozé" tenni. <a href="http://es5.github.io/#x7.6.1">Lásd ES5 Spec</a>.</p> +</div> + +<p>További információk az objektumokról, és prototípusokról a <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype">Object.prototype</a> cikkben olvashatóak. Az obejktumprototípusok, és az objektumprototípus-láncok magyarűzatáhpz lásd az <a href="/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">Inheritance and the prototype chain</a> cikket.</p> + +<div class="note"> +<p>Az ECMAScript 5-től kezdve, az objektumok névpárját (kulcsait) szögletes zárójelek közé tett változóval is lehet használni <code>{[phoneType]: 12345}</code>, nem csak így: <code>var userPhone = {}; userPhone[phoneType] = 12345</code>.</p> +</div> + +<h2 id="Tömbök">Tömbök</h2> + +<p>A tömbök a JavaScriptben az objektumok egy különleges fajtája. Messzemenőkig úgy működnek mint a normális objektumok, (A numerikus tulajdonságok csak a <code>[]</code> szintaxissal érhetőek el) de van egy plusz tulajdonságuk is, a '<code>length</code>'. Ez mindigy egyel több, mint a legmagasabb index a tömbben.</p> + +<p>Egy tömböt a következő képpen lehet létrehozni:</p> + +<pre class="brush: js">var a = new Array(); +a[0] = 'dog'; +a[1] = 'cat'; +a[2] = 'hen'; +a.length; // 3 +</pre> + +<p>Még népszerűbb ezen a módon egy literállal.</p> + +<pre class="brush: js">var a = ['dog', 'cat', 'hen']; +a.length; // 3 +</pre> + +<p>Tartsuk észben, hogy az <code>array.length</code> nem feltétlenül az elemek számát jelenti. Nézzük a következő példát:</p> + +<pre class="brush: js">var a = ['dog', 'cat', 'hen']; +a[100] = 'fox'; +a.length; // 101 +</pre> + +<p>Ne feledjük: a tömb hossza (length) mindig a legmagasabb index + 1 értéket jelenti.</p> + +<p>Ha egy nem létező indexhez próbálunk hozzáférni, akkor <code>undefined</code> értéket kapunk vissza:</p> + +<pre class="brush: js">typeof a[90]; // undefined +</pre> + +<p>A fenti <code>[]</code> -ket és a <code>length</code> tulajdonságot használva, végiglépkedhetünk a tömbön a következő <code>for</code> ciklus segítségével:</p> + +<pre class="brush: js">for (var i = 0; i < a.length; i++) { + // a[i] feldolgozása +} +</pre> + +<p>Az ES2015 óta a fenti módszernek létezik egy egyszerűbb formája is, a <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...of"><code>for</code>...<code>of</code></a> ciklus, ami olyan objektumoknál használható, mint a tömbök:</p> + +<pre class="brush:js">for (const currentValue of a) { + // currentValue feldolgozása +}</pre> + +<p>Egy <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> ciklussal is végig lehet lépkedni egy tömbön, ám ez nem a tömb elemein lépked végig, hanem a tömb indexein. Továbbá, ha valaki új tulajdonságokat ad hozzá az <code>Array.prototype</code>-hoz, akkor azokon is egy ilyen ciklus lépkedne végig. Emiatt ez a fajta ciklus nem ajánlott tömbök iterálására.</p> + +<p>Az ECMAScript 5-ben egy másik módszer is adott, hogy végig lépkedjünk egy tömbön, a <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) { + // currentValue vagy array[index] feldolgozása +}); +</pre> + +<p>Ha egy elemt szeretnénk a tömbhöz hozzáadni, egyszerűen így tehetjük meg:</p> + +<pre class="brush: js">a.push(item);</pre> + +<p>Egy tömbnek sok metódusa van. Lásd a <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">full documentation for array methods</a> cikket is.</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>Egy stringet ad vissza, amiben minden objektum veszzővel van elválasztva. </td> + </tr> + <tr> + <td><code>a.toLocaleString()</code></td> + <td>Egy stringet ad vissza, amiben minden objektum veszzővel van elválasztva, dátumoknál a helyi idő szerinti formátum</td> + </tr> + <tr> + <td><code>a.concat(item1[, item2[, ...[, itemN]]])</code></td> + <td>Egy új tömböt ad vissza, a hozzáadott elemekkel együtt.</td> + </tr> + <tr> + <td><code>a.join(sep)</code></td> + <td>Egy stringé alakítja át a tömböt, amiben a <code>sep</code> paraméterben megadottal lesznek az egyes elemek elválasztva</td> + </tr> + <tr> + <td><code>a.pop()</code></td> + <td>Eltávolítja az utolsó elemet, és visszaadja azt.</td> + </tr> + <tr> + <td><code>a.push(item1, ..., itemN)</code></td> + <td>A tömb végére hozzáfűz egy elemet</td> + </tr> + <tr> + <td><code>a.reverse()</code></td> + <td>Megfordítja a tömb sorrendjét.</td> + </tr> + <tr> + <td><code>a.shift()</code></td> + <td>Eltávolítja az első elemet, és visszaadja azt.</td> + </tr> + <tr> + <td><code>a.slice(start[, end])</code></td> + <td>Egy altömböt ad vissza.</td> + </tr> + <tr> + <td><code>a.sort([cmpfn])</code></td> + <td>Rendezi a tömböt. Opcionálisan egy függvényt is meg lehet adni.</td> + </tr> + <tr> + <td><code>a.splice(start, delcount[, item1[, ...[, itemN]]])</code></td> + <td>Módosít egy tömböt úgy, hogy egy része törölve, és azok több elemekkel cserélve lesznek.</td> + </tr> + <tr> + <td><code>a.unshift(item1[, item2[, ...[, itemN]]])</code></td> + <td>A tömb elejére elemeket szúr be.</td> + </tr> + </tbody> +</table> + +<h2 id="Függvények">Függvények</h2> + +<p>Az objektumok mellet, a függvények a JavaScript központi összetevői. Egy egyszerű függvény szintaxisa alig lehetne egyszerűebb:</p> + +<pre class="brush: js">function add(x, y) { + var total = x + y; + return total; +} +</pre> + +<p>Ez egy egyszerű függvényt mutat be. Egy JavaScript függvénynek 0 vagy több megnevezett paramétere lehet. A függvény törzse tetszüleges számú utasítást tartalmazhat, és egyéni lokális változók is deklarálhatóak benne. A <code>return</code> utasítás bárhol használható értékek visszaadására, és a függvény befejezésére. ha nem használunk <code>return</code> utasítást, (vagy érték nélkül használjuk), a függvény visszatérése <code>undefined</code> lesz.</p> + +<p>A megnevezett paraméterek inkább ajánlás, mint kötelezően megadandó adatok. A függvények meghívhatóak a várt paraméterek nélkül is, ez esetben azok értéke <code>undefined</code> lesz.</p> + +<pre class="brush: js">add(); // NaN +// Nem lehet hozzáadást végezni undefined értékekkel +</pre> + +<p>You can also pass in more arguments than the function is expecting:</p> + +<pre class="brush: js">add(2, 3, 4); // 5 +// az első két paraméter össze lesz adva; a 4 figyelmen kívül marad +</pre> + +<p>Talán egy kicsit furcsának tűnhet, de a függvények a függvénytörzsben hozzáférnek egy plusz változóhoz is, az <a href="/en-US/docs/Web/JavaScript/Reference/Functions/arguments" title="/en/JavaScript/Reference/Functions_and_function_scope/arguments"><code>arguments</code></a>-hez, ami egy tömb szerű objektum, és a megadott paramétereket tartalmazza. Írjuk újra a függvényt úgy hogy tetszőleges számú paramétert dolgozzon fel:</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>Ám ez nem hasznosabb annál, mint leírni, hogy <code>2 + 3 + 4 + 5</code>. Készítsünk egy átlagszámítást végző függvényt:</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>Ez nagyon hasznos, mégis egy kicsit hosszúnak látszik. Hogy lerövidíthessük egy kicsit jobban a kódot, az arguments tömb használatát a <a href="/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">Rest parameter syntax</a> -ra is cserélhetjük, így tetszőleges sok paraméter adható át, és a kód minimális marad. A függvényekben a <strong>rest parameter operator</strong> a <strong>...variable</strong> formátummal írható le, és tartalmazza a függvény számára összes nem megnevezett paramétert. A <strong>for</strong> ciklus helyett használhatunk <strong>for...of</strong> ciklust is.</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">A fenti kódban, az <strong>args</strong> változó tárolja az összes értéket, amit a függvénynek adtunk át.<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 <a href="/en-US/docs/Glossary/IIFE">IIFEs (Immediately Invoked Function Expressions)</a> 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; +} + +var 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; + } + }; +} + +var 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">var 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">var 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 called 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 it. 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> |
