funkcije JavaScript. Ekspresivni JavaScript: Funkcije Javascript, ki vrnejo več vrednosti iz funkcije

Ljudje mislijo, da je računalništvo umetnost za genije. V resnici je ravno obratno – le veliko ljudi dela stvari, ki stojijo ena na drugi, kot da bi iz majhnih kamenčkov delali zid.

Donald Knuth

Videli ste že klice funkcij, kot je opozorilo. Funkcije so kruh in maslo programiranja JavaScript. Zamisel, da bi del programa zavili in ga poklicali kot spremenljivko, je zelo priljubljena. Je orodje za strukturiranje velikih programov, zmanjšanje ponavljanja, poimenovanje podprogramov in izolacijo podprogramov drug od drugega.

Najbolj očitna uporaba funkcij je ustvarjanje novega slovarja. Izmišljanje besed za običajno človeško prozo je slaba oblika. To je potrebno v programskem jeziku.

Povprečen odrasel govorec ruščine pozna približno 10.000 besed. Redek programski jezik vsebuje 10.000 vgrajenih ukazov. In besednjak programskega jezika je bolj jasno definiran, zato je manj prilagodljiv kot človeški. Zato mu moramo običajno dodati svoje besede, da se izognemo nepotrebnemu ponavljanju.

Definicija funkcije Definicija funkcije je običajna definicija spremenljivke, kjer je vrednost, ki jo spremenljivka prejme, funkcija. Naslednja koda na primer definira spremenljivko kvadrat, ki se nanaša na funkcijo, ki izračuna kvadrat danega števila:

Var square = function(x) ( return x * x; ); console.log(kvadrat(12)); // → 144

Funkcijo ustvari izraz, ki se začne s ključno besedo function. Funkcije imajo nabor parametrov (v tem primeru samo x) in telo, ki vsebuje navodila, ki jih je treba izvesti ob klicu funkcije. Telo funkcije je vedno v zavitih oklepajih, tudi če je sestavljena iz enega samega stavka.

Funkcija ima lahko več parametrov ali pa nobenega. V naslednjem primeru makeNoise nima seznama parametrov, moč pa ima dva:

Var makeNoise = function() ( console.log("Sranje!");); naredi hrup (); // → Khrya! var. moč = funkcija (osnova, eksponent) ( sprem. rezultat = 1; for (var. št. = 0; št.< exponent; count++) result *= base; return result; }; console.log(power(2, 10)); // → 1024

Nekatere funkcije vrnejo vrednost, na primer power in square, druge pa ne, na primer makeNoise, ki povzroči le stranski učinek. Stavek return podaja vrednost, ki jo vrne funkcija. Ko programska obdelava doseže to navodilo, takoj zapusti funkcijo in vrne to vrednost na mesto v kodi, iz katerega je bila funkcija poklicana. return brez izraza vrne nedefinirano.

Parametri in obseg Funkcijski parametri so enake spremenljivke, vendar so njihove začetne vrednosti nastavljene ob klicu funkcije in ne v njeni kodi.

Pomembna lastnost funkcij je, da so spremenljivke, ustvarjene znotraj funkcije (vključno s parametri), lokalne za to funkcijo. To pomeni, da bo v primeru moči spremenljivka rezultata ustvarjena vsakič, ko je funkcija poklicana, te njene posamezne inkarnacije pa ne bodo imele nobene zveze druga z drugo.

Ta lokalizacija spremenljivke velja samo za parametre in spremenljivke, ustvarjene znotraj funkcij. Spremenljivke, definirane zunaj katere koli funkcije, se imenujejo globalne, ker so vidne v celotnem programu. Do takih spremenljivk lahko dostopate tudi znotraj funkcije, razen če deklarirate lokalno spremenljivko z istim imenom.

Naslednja koda to ponazarja. Definira in kliče dve funkciji, ki spremenljivki x dodelita vrednost. Prvi ga razglasi za lokalnega in s tem spremeni samo lokalno spremenljivko. Drugi ne deklarira, zato se delo z x znotraj funkcije nanaša na globalno spremenljivko x, definirano na začetku primera.

Var x = "zunaj"; var f1 = function() ( var x = "znotraj f1";); f1(); console.log(x); // → zunaj var f2 = funkcija() ( x = "znotraj f2"; ); f2(); console.log(x); // → znotraj f2

To vedenje pomaga preprečiti nenamerne interakcije med funkcijami. Če bi bile vse spremenljivke uporabljene kjerkoli v programu, bi bilo zelo težko zagotoviti, da ena spremenljivka ni bila uporabljena za različne namene. In če bi znova uporabili spremenljivko, bi naleteli na nenavadne učinke, ko koda tretje osebe pokvari vrednosti vaše spremenljivke. Z obravnavo funkcijskih lokalnih spremenljivk tako, da obstajajo le znotraj funkcije, jezik omogoča delo s funkcijami, kot da bi bile ločena majhna vesolja, kar vam omogoča, da ne skrbite za celotno kodo.

JavaScript z ugnezdenim obsegom razlikuje več kot le med globalnimi in lokalnimi spremenljivkami. Funkcije je mogoče definirati znotraj funkcij, kar povzroči več ravni lokalnosti.

Naslednja precej nesmiselna funkcija na primer vsebuje še dve:

Var landscape = function() ( var result = ""; var flat = function(size) ( for (var count = 0; count< size; count++) result += "_"; }; var mountain = function(size) { result += "/"; for (var count = 0; count < size; count++) result += """; result += "\\"; }; flat(3); mountain(4); flat(6); mountain(1); flat(1); return result; }; console.log(landscape()); // → ___/""""\______/"\_

Funkciji ravnina in gora vidita spremenljivko rezultata, ker sta znotraj funkcije, ki jo definira. Vendar ne moreta videti spremenljivk štetja drug drugega, ker so spremenljivke ene funkcije zunaj obsega druge. In okolje zunaj ležeče funkcije ne vidi nobene od spremenljivk, definiranih znotraj te funkcije.

Skratka, znotraj vsakega lokalnega obsega si lahko ogledate vse obsege, ki ga vsebujejo. Nabor spremenljivk, ki so na voljo znotraj funkcije, je določen z lokacijo, kjer je funkcija deklarirana v programu. Vidne so vse spremenljivke iz blokov, ki obkrožajo definicijo funkcije - vključno s tistimi, ki so definirane na najvišji ravni v glavnem programu. Ta pristop k obsegom se imenuje leksikalni.

Ljudje, ki so študirali druge programske jezike, morda mislijo, da vsak blok, zaprt v zavitih oklepajih, ustvari svoje lokalno okolje. Toda v JavaScriptu samo funkcije ustvarijo obseg. Lahko uporabite samostoječe bloke:

Var nekaj = 1; ( var something = 2; // Naredi nekaj s spremenljivko something ... ) // Izhod iz bloka ...

Toda nekaj znotraj bloka je ista spremenljivka kot zunaj. Čeprav so takšni bloki dovoljeni, jih je smiselno uporabljati samo za stavke if in zanke.

Če se vam to zdi čudno, niste edini, ki tako misli. V različici JavaScript 1.7 se je pojavil ključna beseda let, ki deluje kot var, vendar ustvari spremenljivke, ki so lokalne za kateri koli dani blok, ne le za funkcijo.

Funkcije kot vrednosti Imena funkcij se običajno uporabljajo kot ime za del programa. Takšna spremenljivka se nastavi enkrat in se ne spreminja. Tako je enostavno zamenjati funkcijo in njeno ime.

Ampak to sta dve različni stvari. Klic funkcije je mogoče uporabiti kot preprosto spremenljivko – na primer v katerem koli izrazu. Klic funkcije je mogoče shraniti v novo spremenljivko, jo posredovati kot parameter drugi funkciji itd. Tudi spremenljivka, ki shrani klic funkcije, ostane redna spremenljivka in njeno vrednost je mogoče spremeniti:

Var launchMissiles = funkcija(vrednost) ( ​​missileSystem.launch("ali!");); if (safeMode) launchMissiles = funkcija(vrednost) (/* prekliči */);

V 5. poglavju bomo razpravljali o čudovitih stvareh, ki jih lahko naredite s posredovanjem funkcijskih klicev drugim funkcijam.

Deklariranje funkcij Obstaja krajša različica izraza “var square = function...”. Ključno besedo funkcije lahko uporabite na začetku stavka:

Funkcija square(x) ( return x * x; )

To je deklaracija funkcije. Stavek definira kvadratno spremenljivko in ji dodeli dano funkcijo. Zaenkrat gre dobro. V taki definiciji je samo ena past.

Console.log("Prihodnost pravi:", future()); function future() ( return "ŠE VEDNO nimamo letečih avtomobilov."; )

Ta koda deluje, čeprav je funkcija deklarirana pod kodo, ki jo uporablja. To je zato, ker deklaracije funkcij niso del običajnega izvajanja programa od zgoraj navzdol. "Premaknejo se" na vrh svojega obsega in jih lahko pokliče katera koli koda v tem obsegu. Včasih je to priročno, ker lahko napišete kodo v vrstnem redu, ki je najbolj smiseln, ne da bi vam bilo treba skrbeti, da bi morali definirati vse funkcije zgoraj, kjer se uporabljajo.

Kaj se zgodi, če deklaracijo funkcije postavimo znotraj pogojnega bloka ali zanke? Tega ti ni treba narediti. V preteklosti so različne platforme, ki izvajajo JavaScript, obravnavale takšne primere različno, trenutni jezikovni standard pa to prepoveduje. Če želite, da se vaši programi izvajajo zaporedno, uporabite deklaracije funkcij samo znotraj drugih funkcij ali glavnega programa.

Primer funkcije() ( funkcija a() () // Normalno, če (nekaj) ( funkcija b() () // Aj-jaj-jaj! ) )

Sklad klicev Koristno je, če si podrobneje ogledamo, kako vrstni red izvajanja deluje s funkcijami. Tukaj preprost program z več klici funkcij:

Funkcija greet(who) ( console.log("Pozdravljeni, " + kdo); ) greet("Semyon"); console.log("Pokeda");

Obdeluje se nekako takole: klic greet povzroči, da prehod skoči na začetek funkcije. Pokliče vgrajeno funkcijo console.log, ki prestreže nadzor, opravi svoje in vrne nadzor. Nato pride do konca pozdrava in se vrne na kraj, od koder je bil poklican. Naslednja vrstica znova pokliče console.log.

To lahko shematično prikažemo takole:

Top pozdravi console.log pozdravi zgoraj console.log top

Ker se mora funkcija vrniti na mesto, od koder je bila poklicana, si mora računalnik zapomniti kontekst, iz katerega je bila funkcija poklicana. V enem primeru bi se moral console.log vrniti nazaj na pozdrav. V drugem se vrne na konec programa.

Mesto, kjer si računalnik zapomni kontekst, se imenuje sklad. Ob vsakem klicu funkcije je trenutni kontekst potisnjen na vrh sklada. Ko se funkcija vrne, odstrani zgornji kontekst iz sklada in ga uporabi za nadaljevanje delovanja.

Skladiščenje zahteva prostor v pomnilniku. Ko bo sklad prevelik, bo računalnik prenehal z izvajanjem in sporočil nekaj takega kot "stack overflow" ali "too much recursion." Naslednja koda to dokazuje - računalniku postavi zelo kompleksno vprašanje, ki vodi do neskončnih skokov med dvema funkcijama. Natančneje, šlo bi za neskončne skoke, če bi imel računalnik neskončen sklad. V resnici se sklad preliva.

Funkcija chicken() ( return egg(); ) function egg() ( return chicken(); ) console.log(chicken() + " je bil prvi."); // → ??

Izbirni argumenti Naslednja koda je popolnoma zakonita in deluje brez težav:

Opozorilo ("Pozdravljeni", "Dober večer", "Pozdravljeni vsi!");

Uradno funkcija sprejme en argument. Vendar se ob takšnem izzivu ne pritožuje. Ona ignorira preostale argumente in pokaže "Pozdravljeni."

JavaScript je zelo specifičen glede števila argumentov, posredovanih funkciji. Če prenesete preveč, bodo dodatni prezrti. Premalo in manjkajočim bo dodeljena vrednost nedefinirana.

Slaba stran tega pristopa je, da je mogoče – in celo verjetno – posredovati napačno število argumentov funkciji, ne da bi se kdo pritoževal nad tem.

Prednost je, da lahko ustvarite funkcije, ki sprejemajo neobvezne argumente. Na primer, v naslednji različici potenčne funkcije jo je mogoče poklicati z dvema ali enim argumentom – v slednjem primeru bo eksponent enak dve, funkcija pa deluje kot kvadrat.

Funkcijska moč (osnova, eksponent) ( if (eksponent == nedefinirano) eksponent = 2; sprem. rezultat = 1; for (var count = 0; count< exponent; count++) result *= base; return result; } console.log(power(4)); // → 16 console.log(power(4, 3)); // → 64

V naslednjem poglavju bomo videli, kako lahko v telesu funkcije ugotovite natančno število argumentov, ki so ji bili posredovani. To je koristno, ker ... omogoča ustvarjanje funkcije, ki sprejme poljubno število argumentov. Na primer, console.log uporablja to lastnost in natisne vse argumente, ki so ji bili posredovani:

Console.log("R", 2, "D", 2); // → R 2 D 2

Zaprtja Zmožnost uporabe funkcijskih klicev kot spremenljivk, skupaj z dejstvom, da se lokalne spremenljivke ustvarijo na novo vsakič, ko je funkcija priklicana, nas vodi do zanimivega vprašanja. Kaj se zgodi z lokalnimi spremenljivkami, ko funkcija preneha delovati?

Naslednji primer ponazarja to težavo. Deklarira funkcijo wrapValue, ki ustvari lokalno spremenljivko. Nato vrne funkcijo, ki prebere to lokalno spremenljivko in vrne njeno vrednost.

Funkcija wrapValue(n) ( var localVariable = n; return function() ( return localVariable; ); ) var wrap1 = wrapValue(1); var wrap2 = wrapValue(2); console.log(wrap1()); // → 1 console.log(wrap2()); // → 2

To je veljavno in deluje kot mora - dostop do spremenljivke ostane. Poleg tega lahko istočasno obstaja več primerkov iste spremenljivke, kar dodatno potrjuje dejstvo, da se lokalne spremenljivke znova ustvarijo z vsakim klicem funkcije.

Ta zmožnost dela s sklicevanjem na primerek lokalne spremenljivke se imenuje zaprtje. Funkcija, ki zapre lokalne spremenljivke, se imenuje zapiranje. Ne le, da vas osvobodi skrbi glede spremenljivih življenjskih dob, ampak vam omogoča tudi ustvarjalno uporabo funkcij.

Z majhno spremembo naš primer spremenimo v funkcijo, ki množi števila s poljubnim številom.

Funkcija množitelj(faktor) ( vrni funkcijo(število) ( vrni število * faktor; ); ) var dvakrat = množitelj(2); console.log(dvakrat(5)); // → 10

Ločena spremenljivka, kot je localVariable iz primera wrapValue, ni več potrebna. Ker je parameter sam po sebi lokalna spremenljivka.

Potrebna bo praksa, da začnete tako razmišljati. Dobra možnost mentalni model je predstavljati, da funkcija zamrzne kodo v svojem telesu in jo zavije v embalažo. Ko vidite return function(...) (...), si predstavljajte to kot nadzorno ploščo za kos kode, ki je zamrznjen za kasnejšo uporabo.

V našem primeru multiplikator vrne zamrznjen del kode, ki ga shranimo v spremenljivko two. Zadnja vrstica pokliče funkcijo v spremenljivki, ki povzroči aktiviranje shranjene kode (povratna številka * faktor;). Še vedno ima dostop do faktorske spremenljivke, ki je bila definirana pri klicu množitelja, in ima tudi dostop do argumenta, posredovanega med odmrzovanjem (5) kot številski parameter.

Rekurzija Funkcija lahko kliče sama sebe, če pazi, da ne prepolni sklada. Ta funkcija se imenuje rekurzivna. Tukaj je primer alternativne izvedbe stopnjevanja:

Funkcija power(osnova, eksponent) ( if (eksponent == 0) vrne 1; sicer vrne osnovo * power(osnova, eksponent - 1); ) console.log(power(2, 3)); // → 8

Približno tako matematiki definirajo potenciranje in morda to opisuje koncept bolj elegantno kot cikel. Funkcija se večkrat pokliče z različnimi argumenti, da doseže večkratno množenje.

Vendar pa je pri tej izvedbi težava: normalno okolje JavaScript je 10-krat počasnejši od različice z zanko. Hoja skozi zanko je cenejša od klicanja funkcije.

Dilema hitrost proti eleganci je zelo zanimiva. Obstaja določen razkorak med udobjem za ljudi in udobjem za stroje. Vsak program lahko pospešimo tako, da ga naredimo večjega in bolj zapletenega. Programer mora najti ustrezno ravnotežje.

V primeru prvega potenciranja je neelegantna zanka precej preprosta in enostavna. Nima smisla zamenjati z rekurzijo. Pogosto pa se programi ukvarjajo s tako kompleksnimi koncepti, da se želi učinkovitost zmanjšati s povečanjem berljivosti.

Osnovno pravilo, ki je bilo že večkrat ponovljeno in s katerim se popolnoma strinjam, je, da ne skrbite za delovanje, dokler niste popolnoma prepričani, da se program upočasnjuje. Če je tako, poiščite dele, ki trajajo najdlje, in tam zamenjajte eleganco za učinkovitost.

Seveda pa ne smemo kar takoj zanemariti uspešnosti. V mnogih primerih, tako kot pri potenciranju, z elegantnimi rešitvami ne dobimo veliko preprostosti. včasih izkušen programer takoj vidi, da preprost pristop nikoli ne bo dovolj hiter.

To izpostavljam, ker je preveč programerjev začetnikov obsedenih z učinkovitostjo že pri majhnih stvareh. Rezultat je večji, bolj zapleten in pogosto ni brez napak. Takšni programi se pišejo dlje, vendar pogosto ne delujejo veliko hitreje.

Toda rekurzija ni vedno le manj učinkovita alternativa zankam. Nekatere probleme je lažje rešiti z rekurzijo. Najpogosteje je to prečkanje več vej drevesa, od katerih se lahko vsaka razveji.

Tukaj je uganka: neskončno število števil lahko dobite tako, da začnete s številko 1 in nato dodate 5 ali pomnožite s 3. Kako napišemo funkcijo, ki skuša po določenem številu najti zaporedje seštevanj in množenj ki vodijo do določene številke? Na primer, število 13 lahko dobite tako, da najprej pomnožite 1 s 3 in nato dvakrat dodate 5. In številke 15 na ta način sploh ni mogoče dobiti.

Rekurzivna rešitev:

Function findSolution(target) ( function find(start, history) ( if (start == target) vrni zgodovino; else if (start > target) vrni nič; sicer vrni find(start + 5, "(" + history + " + 5)") || find(start * 3, "(" + history + " * 3)"); ) return find(1, "1"); ) console.log(findSolution(24)); // → (((1 * 3) + 5) * 3)

Ni nujno, da ta primer najde najkrajšo rešitev - zadovolji ga katera koli. Ne pričakujem, da boste takoj razumeli, kako program deluje. Toda razumejmo to odlično vajo rekurzivnega razmišljanja.

Notranja funkcija find izvaja rekurzijo. Potrebuje dva argumenta - trenutno številko in niz, ki vsebuje zapis o tem, kako smo prišli do te številke. In vrne niz, ki prikazuje naše zaporedje korakov, ali nič.

Za to funkcija izvede eno od treh dejanj. Če je podana številka enaka cilju, potem je trenutna zgodba prav pot do tega, zato se vrača. Če je dano število večje od cilja, nima smisla nadaljevati z množenjem in seštevanjem, saj se bo le še povečalo. In če še nismo dosegli cilja, funkcija poskusi oboje možne načine, začenši z dano številko. Prikliče se dvakrat, z vsako metodo enkrat. Če prvi klic ne vrne ničelne vrednosti, se vrne. V drugem primeru se drugi vrne.

Da bi bolje razumeli, kako funkcija doseže želeni učinek, si oglejmo klice, ki jih naredi, da bi našli rešitev za številko 13.

Najdi (1, "1") najdi (6, "(1 + 5)") najdi (11, "((1 + 5) + 5)") najdi (16, "(((1 + 5) + 5 ) + 5)") prevelika najdba(33, "(((1 + 5) + 5) * 3)") prevelika najdba(18, "((1 + 5) * 3)") prevelika najdba( 3, "(1 * 3)") najdi (8, "((1 * 3) + 5)") najdi (13, "(((1 * 3) + 5) + 5)") najdeno!

Vdolbina prikazuje globino sklada klicev. Prvič se funkcija iskanja dvakrat pokliče, da preveri rešitve, ki se začnejo z (1 + 5) in (1 * 3). Prvi klic išče rešitev, ki se začne z (1 + 5), in uporablja rekurzijo za preverjanje vseh rešitev, ki proizvedejo število, ki je manjše ali enako zahtevanemu številu. Ne najde in vrne nič. Nato operator || in preide na klic funkcije, ki preuči možnost (1 * 3). Tu imamo srečo, saj v tretjem rekurzivnem klicu dobimo 13. Ta klic vrne niz in vsak od || na poti gre mimo te črte višje, kar povzroči vrnitev rešitve.

Rastoče funkcije Obstajata dva bolj ali manj naravna načina za uvedbo funkcij v program.

Prvi je, da večkrat napišete podobno kodo. Temu se je treba izogibati – več kode pomeni več prostora za napake in več bralnega gradiva za tiste, ki poskušajo razumeti program. Zato vzamemo ponavljajočo se funkcionalnost in jo uskladimo dobro ime in ga postavite v funkcijo.

Drugi način je, da odkrijete potrebo po neki novi funkcionalnosti, ki je vredna, da bi jo postavili v ločeno funkcijo. Začnete z imenom funkcije in nato napišete njeno telo. Začnete lahko celo tako, da napišete kodo, ki uporablja funkcijo, preden je funkcija sama definirana.

Kako težko vam je poimenovati funkcijo, kaže, kako dobro razumete njeno funkcionalnost. Vzemimo primer. Napisati moramo program, ki izpiše dve števili, število krav in piščancev na kmetiji, ki jima sledita besedi »krave« in »piščanci«. Številkam pred njimi morate dodati ničle, tako da bo vsaka zasedla natanko tri mesta.

007 Krave 011 Piščanci

Očitno potrebujemo funkcijo z dvema argumentoma. Začnimo s kodiranjem.
// natisni funkcijo FarmInventory printFarmInventory(krave, piščanci) ( var cowString = String(cows); medtem ko (cowString.length< 3) cowString = "0" + cowString; console.log(cowString + " Коров"); var chickenString = String(chickens); while (chickenString.length < 3) chickenString = "0" + chickenString; console.log(chickenString + " Куриц"); } printFarmInventory(7, 11);

Če nizu dodamo .length, dobimo njegovo dolžino. Izkazalo se je, da medtem ko zankeštevilkam dodajajte vodilne ničle, dokler ne dobite niza s 3 znaki.

pripravljena! A ravno ko smo kmetu želeli poslati šifro (seveda z zajetnim čekom), pokliče in pove, da ima na kmetiji prašiče in ali bi lahko dodali še prikaz števila prašičev. program?

Seveda je možno. Toda ko začnemo kopirati in lepiti kodo iz teh štirih vrstic, ugotovimo, da se moramo ustaviti in razmisliti. Mora obstajati boljši način. Trudimo se izboljšati program:

// izpis Z dodajanjem ničel IN oznak funkcija printZeroPaddedWithLabel(number, label) ( var numberString = String(number); while (numberString.length< 3) numberString = "0" + numberString; console.log(numberString + " " + label); } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { printZeroPaddedWithLabel(cows, "Коров"); printZeroPaddedWithLabel(chickens, "Куриц"); printZeroPaddedWithLabel(pigs, "Свиней"); } printFarmInventory(7, 11, 3);

deluje! Toda ime printZeroPaddedWithLabel je nekoliko čudno. Združuje tri stvari – izpis, dodajanje ničel in oznako – v eno funkcijo. Namesto vstavljanja celotnega ponavljajočega se fragmenta v funkcijo, poudarimo en koncept:

// dodaj ničelno funkcijo zeroPad(število, širina) ( var string = String(število); medtem ko (string.length< width) string = "0" + string; return string; } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { console.log(zeroPad(cows, 3) + " Коров"); console.log(zeroPad(chickens, 3) + " Куриц"); console.log(zeroPad(pigs, 3) + " Свиней"); } printFarmInventory(7, 16, 3);

Funkcija z lepim, jasnim imenom zeroPad olajša razumevanje kode. In lahko se uporablja v mnogih situacijah, ne samo v našem primeru. Na primer za prikaz oblikovanih tabel s številkami.

Kako pametne in vsestranske naj bodo funkcije? Napišemo lahko bodisi preprosto funkcijo, ki doda številko z ničlami ​​do treh mest, bodisi prefinjeno funkcijo glavni namen za oblikovanje števil, podporne ulomke, negativna števila, poravnavo pik, polnjenje z različnimi znaki itd.

Dobro pravilo je, da dodate samo funkcije, za katere veste, da bodo uporabne. Včasih je skušnjava ustvariti okvire splošnega namena za vsako najmanjšo potrebo. Uprite se mu. Nikoli ne boste dokončali dela, na koncu boste samo napisali kup kode, ki je nihče ne bo uporabil.

Funkcije in stranski učinki Funkcije lahko v grobem razdelimo na tiste, ki so priklicane zaradi stranskih učinkov, in tiste, ki so priklicane, da pridobijo neko vrednost. Seveda je možno tudi združiti te lastnosti v eni funkciji.

Prva pomožna funkcija v primeru farme, printZeroPaddedWithLabel, je poklicana, ker ima stranski učinek: natisne niz. Drugi, zeroPad, zaradi vrnjene vrednosti. In ni naključje, da druga funkcija pride prav pogosteje kot prva. Funkcije, ki vračajo vrednosti, je lažje kombinirati med seboj kot funkcije, ki povzročajo stranske učinke.

Čista funkcija je posebna vrsta funkcije za vračanje vrednosti, ki nima samo stranskih učinkov, ampak tudi ni odvisna od stranskih učinkov preostale kode – na primer, ne deluje z globalnimi spremenljivkami, ki bi jih lahko pomotoma spremenili nekje drugje. Čista funkcija, ko je poklicana z istimi argumenti, vrne enak rezultat (in ne naredi nič drugega) - kar je zelo lepo. Z njo je enostavno delati. Klic takšne funkcije je mogoče mentalno nadomestiti z rezultatom njenega dela, ne da bi spremenili pomen kode. Ko želite preizkusiti takšno funkcijo, jo lahko preprosto pokličete in ste prepričani, da če deluje v danem kontekstu, bo delovala v katerem koli kontekstu. Manj čiste funkcije lahko vrnejo različne rezultate, odvisno od številnih dejavnikov, in imajo stranske učinke, ki jih je težko preizkusiti in upoštevati.

Vendar pa naj vam ne bo nerodno napisati funkcije, ki niso povsem čiste, ali začeti sveto čiščenje kode takih funkcij. Stranski učinki so pogosto koristni. Ni načina za pisanje čiste različice funkcije console.log in ta funkcija je zelo uporabna. Nekatere operacije je lažje izraziti s stranskimi učinki.

Povzetek To poglavje vam je pokazalo, kako napisati lastne funkcije. Ko je ključna beseda funkcije uporabljena kot izraz, vrne kazalec na klic funkcije. Ko jo uporabljate kot navodilo, lahko deklarirate spremenljivko tako, da ji dodelite klic funkcije.

Ključ do razumevanja funkcij je lokalni obseg. Parametri in spremenljivke, deklarirane znotraj funkcije, so lokalni zanjo, se znova ustvarijo ob vsakem klicu in niso vidni od zunaj. Funkcije, deklarirane znotraj druge funkcije, imajo dostop do njenega obsega.

Zelo koristno je ločiti različne naloge, ki jih izvaja program, na funkcije. Ni se vam treba ponavljati; funkcije naredijo kodo bolj berljivo, tako da jo razdelijo na pomembne dele, tako kot poglavja in deli knjige pomagajo organizirati običajno besedilo.

VajeMinimum V prejšnjem poglavju smo omenili funkcijo Math.min, ki vrne najmanjši od svojih argumentov. Zdaj lahko takšno funkcijo napišemo sami. Napišite funkcijo min, ki sprejme dva argumenta in vrne najmanjši izmed njih.

Console.log(min(0, 10)); // → 0 console.log(min(0, -10)); // → -10

Rekurzija Videli smo, da lahko operator % (modulo) uporabimo za ugotavljanje, ali je število (%2) sodo. Tukaj je še en način za opredelitev:

Nič je sodo.
Enota je čudna.
Vsako število N ima enako pariteto kot N-2.

Napišite rekurzivno funkcijo isEven v skladu s temi pravili. Sprejeti mora število in vrniti logično vrednost.

Preizkusite ga pri 50 in 75. Poskusite dati -1. Zakaj se tako obnaša? Ali je to mogoče nekako popraviti?

Preizkusite ga na 50 in 75. Poglejte, kako se obnaša na -1. Zakaj? Ali lahko pomislite, kako bi to popravili?

Console.log(isEven(50)); // → true console.log(isEven(75)); // → false console.log(isEven(-1)); // → ??

Štetje fižola.

Številko znaka N niza lahko dobite tako, da mu dodate .charAt(N) (“string”.charAt(5)) – na podoben način kot pridobivanje dolžine niza z uporabo .length. Povratna vrednost bo niz, sestavljen iz enega znaka (na primer »k«). Prvi znak niza ima položaj 0, kar pomeni, da bo imel zadnji znak položaj string.length - 1. Z drugimi besedami, niz dveh znakov ima dolžino 2, njegova položaja znakov pa bosta 0 in 1.

Napišite funkcijo countBs, ki vzame niz kot argument in vrne število znakov »B« v nizu.

Nato napišite funkcijo, imenovano countChar, ki deluje podobno kot countBs, vendar sprejme drugi parameter - znak, ki ga bomo iskali v nizu (namesto samo štetja števila znakov "B"). Če želite to narediti, predelajte funkcijo countBs.

Funkcije so eden najpomembnejših gradnikov kode v JavaScriptu.

Funkcije so sestavljene iz nabora ukazov in običajno izvajajo enega določeno nalogo(na primer seštevanje števil, računanje korenov itd.).

Koda, nameščena v funkciji, bo izvedena šele po eksplicitnem klicu te funkcije.

Deklaracija funkcije

1. Sintaksa:

//Deklaracija funkcije functionFunctionname(ln1, ln2)( koda funkcije) //Klic funkcijeFunctionname(ln1,lr2);

2. Sintaksa:

//Deklaracija funkcije var function name=function(ln1, ln2)(koda funkcije) //Klic funkcije function name(ln1,lr2);

functionname podaja ime funkcije. Vsaka funkcija na strani mora imeti edinstveno ime. Ime funkcije mora biti podano z latiničnimi črkami in se ne sme začeti s številkami.

ln1 in ln2 sta spremenljivki ali vrednosti, ki ju je mogoče posredovati v funkcijo. Vsaki funkciji je mogoče posredovati neomejeno število spremenljivk.

Prosimo, upoštevajte: tudi če v funkcijo ni posredovana nobena spremenljivka, ne pozabite vstaviti oklepaja "()" za imenom funkcije.

Upoštevajte, da imena funkcij v JavaScriptu razlikujejo med velikimi in malimi črkami.

Primer funkcije JavaScript

Funkcija messageWrite() v spodnjem primeru se bo izvedla šele po kliku gumba.

Upoštevajte, da ta primer uporablja dogodek onclick. JavaScript dogodki bomo podrobneje obravnavali kasneje v tem učbeniku.

// Funkcija zapiše besedilo na stran function messageWrite() (document.write("To besedilo je bilo zapisano na stran z uporabo JavaScript!"); )

Posredovanje spremenljivk funkcijam

Funkcijam lahko posredujete neomejeno število spremenljivk.

Upoštevajte: vse manipulacije s spremenljivkami znotraj funkcij se dejansko ne izvajajo na samih spremenljivkah, temveč na njihovi kopiji, zato se vsebina samih spremenljivk ne spremeni zaradi izvajanja funkcij.

/* Definirajmo funkcijo, ki doda 10 posredovani spremenljivki in prikaže rezultat na strani */ function plus(a)( a=a+10; document.write("Izhod funkcije: " + a+"
"); ) var a=25; document.write("Vrednost spremenljivke pred klicem funkcije: "+a+"
"); // Pokličite funkcijo tako, da ji posredujete spremenljivko a plus(a); document.write("Vrednost spremenljivke po klicu funkcije: "+a+"
");

Hiter pogled

Za dostop do globalne spremenljivke iz funkcije namesto njene kopije uporabite window.variable_name.

Funkcija plus(a)( window.a=a+10; ) var a=25; document.write("Vrednost spremenljivke pred klicem funkcije: "+a+"
"); plus(a); document.write("Vrednost spremenljivke po klicu funkcije: "+a+"
");

Hiter pogled

povratni ukaz

Z ukazom return lahko vrnete vrednosti iz funkcij.

//Funkcija sum vrne vsoto spremenljivk, ki so ji bile posredovane function sum(v1,v2)( return v1+v2; ) document.write("5+6=" + sum(5,6) + "
"); document.write("10+4=" + vsota(10,4) + "
");

Hiter pogled

Vgrajene funkcije

Poleg uporabniško definiranih funkcij ima JavaScript tudi vgrajene funkcije.

Na primer, vgrajena funkcija isFinite vam omogoča, da preverite, ali je posredovana vrednost veljavno število.

Document.write(isFinite(40)+"
"); document.write(isFinite(-590)+"
"); document.write(isFinite(90.33)+"
"); document.write(isFinite(NaN)+"
"); document.write(isFinite("To je niz")+"
");

Hiter pogled

Opomba: celoten seznam vgrajena funkcije JavaScript Najdete ga v našem.

Lokalne in globalne spremenljivke

Spremenljivke, ustvarjene znotraj funkcij, imenujemo lokalne spremenljivke. Do teh spremenljivk lahko dostopate samo znotraj funkcij, v katerih so bile definirane.

Ko se koda funkcije zaključi z izvajanjem, se takšne spremenljivke uničijo. To pomeni, da lahko spremenljivke z istim imenom definiramo v različnih funkcijah.

Spremenljivke, ki so ustvarjene zunaj funkcijske kode, se imenujejo globalne spremenljivke; do takšnih spremenljivk je mogoče dostopati od kjer koli v kodi.

Če deklarirate spremenljivko brez var znotraj funkcije, postane tudi globalna.

Globalne spremenljivke se uničijo šele, ko se stran zapre.

//Deklariraj globalni spremenljivki var1 in var2 var var1="var1 obstaja"; var var2; funkcija func1() ( //Dodeli var2 vrednost znotraj funkcije func1 var var2="var2 obstaja"; ) //Iz druge funkcije natisni vsebino spremenljivk var1 in var2 na funkcijo strani func2() ( //Natisni vsebina spremenljivke var1 document.write( var1 + "
"); //Izpis vsebine spremenljivke var2 document.write(var2); )

Hiter pogled

Upoštevajte, da bo imela var2 prazno vrednost, ko bo natisnjena na zaslon, ker func1 deluje na lokalni "različici" var2.

Uporaba anonimnih funkcij

Funkcije, ki ob deklaraciji ne vsebujejo imena, se imenujejo anonimne.

Anonimne funkcije so v bistvu deklarirane tako, da se naknadno ne kličejo iz kode kot običajne funkcije, ampak da se posredujejo drugim funkcijam kot parameter.

Funkcija arrMap(arr,func)( var res=nova matrika; for (var i=0;i