Js-funktion päättymislausekkeet. JavaScript-toiminnot. Toiminnot ja sivuvaikutukset

Hyppylausunnot ja poikkeusten käsittely

Toinen JavaScript-operaattoreiden luokka ovat hyppy-operaattorit. Kuten nimestä voi päätellä, nämä operaattorit saavat JavaScript-tulkin siirtymään toiseen paikkaan ohjelmakoodissa. Break-lause saa tulkin hyppäämään silmukan tai muun käskyn loppuun. Jatka-käsky saa tulkin ohittamaan loput silmukan rungosta, hyppäämään takaisin silmukan alkuun ja aloittamaan uuden iteroinnin. JavaScript pystyy merkitsemään lausekkeita nimillä, joten katkaisevat ja jatkavat lausekkeet voivat osoittaa selvästi, mihin silmukkaan tai muuhun lauseeseen ne kuuluvat.

Return-lause saa tulkin hyppäämään kutsutusta funktiosta takaisin kohtaan, jossa sitä kutsuttiin, ja palauttamaan kutsun arvon. heitto-käsky herättää poikkeuksen ja on suunniteltu toimimaan yhdessä try/catch/finally-lausekkeiden kanssa, jotka määrittelevät koodilohkon poikkeuksen käsittelemiseksi. Tämä on melko monimutkainen hyppyoperaattori: kun poikkeus tapahtuu, tulkki hyppää lähimpään sulkevaan poikkeuskäsittelijään, joka voi olla samassa funktiossa tai korkeammalla kutsutun funktion paluupinossa.

Kaikki nämä hyppyoperaattorit kuvataan yksityiskohtaisemmin seuraavissa alaosissa.

Ohje merkit

Mikä tahansa ohje voidaan merkitä tunnisteella ja kaksoispisteellä:

ID: ohje

Merkitsemällä käskyn annat sille nimen, jota voidaan sitten käyttää viitteenä missä tahansa ohjelmassa. Voit merkitä minkä tahansa käskyn, mutta on järkevää merkitä vain käskyt, joilla on runko, kuten silmukat ja ehdolliset lauseet.

Määrittämällä silmukalle nimen, sitä voidaan sitten käyttää break and jatku -lauseissa, silmukan sisällä silmukasta poistumiseen tai silmukan alkuun siirtymiseen seuraavaan iteraatioon. Katko- ja jatka-lauseet ovat ainoita JavaScript-lauseita, jotka voivat sisältää tunnisteita – käsittelemme niitä tarkemmin myöhemmin. Seuraavassa on esimerkki while-lauseesta, jossa on otsikko ja jatka-lauseke, joka käyttää tätä tunnistetta:

Mainloop: while (token != null) ( // Ohjelmakoodi jätetty pois... jatka pääsilmukkaa; // Siirry nimetyn silmukan seuraavaan iteraatioon)

Lauseketunnisteena käytettävä tunniste voi olla mikä tahansa kelvollinen JavaScript-tunniste paitsi varattu sana. Tunnisteiden nimet erotetaan muuttujien ja funktioiden nimistä, joten tunnisteina voidaan käyttää muuttujien tai funktioiden nimiä vastaavia tunnisteita.

Ohjetarrat määritellään vain ohjeissa, joita ne koskevat (ja tietysti niihin sisäkkäisissä ohjeissa). Sisäkkäisiä lausekkeita ei voi merkitä samoilla tunnisteilla kuin ne sisältävät lausekkeet, mutta kaksi itsenäistä lauseketta voidaan merkitä samalla tunnisteella. Merkityt ohjeet voidaan merkitä uudelleen. Eli missä tahansa ohjeessa voi olla useita tarroja.

katkeaa lausunto

Break-käsky saa sisimmän silmukan tai kytkinkäskyn poistumaan välittömästi. Olemme aiemmin nähneet esimerkkejä break-lauseen käyttämisestä kytkinkäskyn sisällä. Silmukoissa sitä käytetään yleensä välittömästi poistumaan silmukasta, kun silmukan on jostain syystä päätettävä.

Kun silmukalla on erittäin monimutkaiset lopetusehdot, on usein helpompi toteuttaa ne lyhennelauseella kuin yrittää ilmaista ne yhdellä silmukan ehtolausekkeella. Seuraava esimerkki yrittää löytää taulukkoelementin tietyllä arvolla. Silmukka päättyy normaalisti, kun se saavuttaa taulukon lopun, tai break-lauseeseen, kun etsittävä arvo löytyy:

Var arr = ["a","b","c","d","d"], tulos; for (var i = 0; i

JavaScriptissä voit määrittää tunnisteen nimen break-avainsanan jälkeen (tunniste ilman kaksoispistettä):

katkaista etiketin_nimi;

Kun break-lausetta käytetään tunnisteen kanssa, se hyppää nimetyn käskyn loppuun tai lopettaa sen suorittamisen. Jos määritetyllä tunnisteella ei ole käskyä, tämän muodon break-lauseen yrittäminen tuottaa syntaksivirheen. Nimetyn käskyn ei tarvitse olla silmukka- tai kytkinkäsky. Katkolauseke, jossa on tunniste, voi irtautua mistä tahansa sisältävästä lauseesta. Käärimisohje voi jopa olla yksinkertainen ohjesarja, joka on suljettu kihariin aaltosulkeisiin, joiden ainoa tarkoitus on merkitä se.

Et voi lisätä rivinvaihtomerkkiä vaihtoavainsanan ja tunnisteen nimen väliin. Tämä johtuu siitä, että JavaScript-tulkki lisää automaattisesti puuttuvat puolipisteet: jos jaat koodirivin break-avainsanan ja seuraavan tunnisteen väliin, tulkki olettaa, että tarkoitit lauseen yksinkertaista muotoa ilman tunnistetta, ja lisää puolipisteen.

Merkittyä break-lausetta tarvitaan vain, kun haluat keskeyttää sellaisen käskyn suorittamisen, joka ei ole lähin sulkeva silmukka tai kytkinkäsky.

Jatka operaattoria

Jatka-lause on samanlainen kuin break-lause. Silmukasta poistumisen sijaan jatka-käsky aloittaa silmukan uuden iteraation. Continue-lauseen syntaksi on yhtä yksinkertainen kuin break-lauseen syntaksi. Jatka-lausetta voidaan käyttää myös etiketin kanssa.

Jatka-lausetta, sekä muodossa ilman otsikkoa että etikettiä, voidaan käyttää vain silmukan rungossa. Sen käyttäminen missä tahansa muualla johtaa syntaksivirheeseen. Kun jatka-käsky suoritetaan, silmukan nykyinen iteraatio keskeytyy ja seuraava alkaa. Tämä tarkoittaa eri asioita erityyppisille silmukoille:

    Jonkin ajan silmukassa silmukan alussa määritetty lauseke tarkistetaan uudelleen, ja jos se on tosi, silmukan runko suoritetaan alusta.

    Do/while -silmukka hyppää silmukan loppuun, jossa ehto tarkistetaan uudelleen ennen silmukan uudelleen suorittamista.

    For-silmukka arvioi lisäyslausekkeen ja arvioi testilausekkeen uudelleen määrittääkseen, tuleeko seuraava iteraatio suorittaa.

    For/in-silmukassa silmukka alkaa alusta määrittämällä määritetty muuttuja seuraavan ominaisuuden nimeen.

Huomaa erot jatkuvuuskäskyn käyttäytymisessä while- ja for-silmukoissa. While-silmukka palaa suoraan ehtoonsa, kun taas for-silmukka arvioi ensin lisäyslausekkeen ja palaa sitten ehtoon. Seuraava esimerkki näyttää jatka-käskyn käytön ilman tunnistetta parillisten lukujen nykyisen silmukan iteraatiosta poistumiseen:

Var summa = 0; // Laske parittomien lukujen summa 0-10 arvolle (muut i = 0; i

Continue-lausetta, kuten break, voidaan käyttää sisäkkäisissä silmukoissa muodossa, joka sisältää tunnisteen, jolloin uudelleen käynnistettävä silmukka ei välttämättä ole silmukka, joka sisältää suoraan jatka-käskyn. Lisäksi rivinvaihdot eivät ole sallittuja jatka-avainsanan ja tunnisteen nimen välissä, kuten tauon kohdalla.

palautusilmoitus

Funktiokutsu on lauseke ja, kuten kaikilla lausekkeilla, sillä on arvo. Funktioiden sisällä olevaa return-lausetta käytetään määrittämään funktion palauttama arvo. Return-lause voi esiintyä vain funktion rungossa. Sen läsnäolo missä tahansa muussa paikassa on syntaksivirhe. Kun return-käsky suoritetaan, funktio palauttaa lausekkeen arvon kutsuvalle ohjelmalle. Esimerkiksi:

Jos funktiolla ei ole return-käskyä, tulkki suorittaa sitä kutsuttaessa funktion rungossa olevat käskyt yksitellen, kunnes se saavuttaa funktion loppuun, ja palauttaa sitten ohjauksen sen kutsuneelle ohjelmalle. Tässä tapauksessa kutsuva lauseke palauttaa määrittelemättömän. Return-käsky on usein funktion viimeinen lauseke, mutta se on täysin valinnainen: funktio palauttaa ohjauksen kutsuvalle ohjelmalle heti, kun return-käsky on saavutettu, vaikka sitä seuraisi muita funktion rungon käskyjä.

Return-käskyä voidaan käyttää myös ilman lauseketta, jolloin se yksinkertaisesti keskeyttää funktion ja palauttaa määrittelemättömän kutsuvaan ohjelmaan. Esimerkiksi:

Funktio myFun(arr) ( // Jos taulukko sisältää negatiivisia lukuja, keskeytä funktio (var i = 0; i

heittää lausunto

Poikkeus on signaali, joka ilmaisee, että jokin poikkeustilanne tai virhe on tapahtunut. Poikkeuksen heittäminen on tapa ilmoittaa tällaisesta virheestä tai poikkeuksesta. Poikkeuksen saaminen kiinni tarkoittaa sen prosessointia, ts. ryhtyä tarpeellisiin tai asianmukaisiin toimiin poikkeuksesta toipumiseksi.

JavaScriptissä poikkeukset heitetään, kun tapahtuu ajonaikainen virhe ja kun ohjelma nimenomaisesti nostaa sen käyttämällä throw-lausetta. Poikkeukset saadaan kiinni käyttämällä try/catch/finally-lauseita, jotka kuvataan myöhemmin.

Heittolauseella on seuraava syntaksi:

heittää ilme;

Lausekkeen tulos voi olla minkä tahansa tyyppinen arvo. Heittokäsky voidaan välittää numero, joka edustaa virhekoodia tai merkkijonoa, joka sisältää virheilmoituksen tekstin. JavaScript-tulkki heittää poikkeuksia käyttämällä jonkin alaluokkansa Error-luokan esiintymää, ja voit käyttää samanlaista lähestymistapaa. Error-objektilla on ominaisuus nimi, joka määrittää virheen tyypin ja ominaisuuden viesti joka sisältää konstruktorifunktiolle välitetyn merkkijonon. Seuraavassa on esimerkki funktiosta, joka herättää Error-objektin, kun sitä kutsutaan virheellisellä argumentilla:

// Numerotekijäfunktiofunktio factorial(number) ( // Jos syöteargumentti ei ole kelvollinen arvo, // annetaan poikkeus! if (numero 1; i *= numero, numero--); /* tyhjä silmukan runko */ return i ; ) console.log("5! = ", factorial(5)); console.log("-3! = ", factorial(-3));

Kun poikkeus nostetaan esiin, JavaScript-tulkki keskeyttää välittömästi ohjelman normaalin suorituksen ja hyppää lähimpään poikkeuskäsittelijään. Poikkeuskäsittelijät käyttävät try/catch/finally catch -lausetta, joka kuvataan seuraavassa osiossa.

Jos koodilohkolla, jossa poikkeus tapahtui, ei ole vastaavaa catch-rakennetta, tulkki tutkii seuraavan ulomman koodilohkon ja tarkistaa, onko siihen liitetty poikkeuskäsittelijä. Tämä jatkuu, kunnes ohjaaja löytyy.

Jos poikkeus heitetään funktioon, joka ei sisällä try/catch/finally-konstruktiota sen käsittelemiseksi, poikkeus etenee funktiota kutsuneeseen koodiin. Tällä tavalla poikkeukset leviävät JavaScript-menetelmien leksikaalisen rakenteen kautta kutsupinoon. Jos poikkeuskäsittelijää ei koskaan löydy, poikkeusta käsitellään virheenä ja raportoidaan käyttäjälle.

kokeile/saappaa/vihdoin rakentaa

Try/catch/finally -konstruktio toteuttaa poikkeusten käsittelymekanismin JavaScriptissä. Tämän rakenteen try-lause määrittää yksinkertaisesti koodilohkon, jossa poikkeuksia käsitellään. Try-lohkoa seuraa catch-lause, jossa on lausekelohko, joita kutsutaan, jos jossain try-lohkossa tapahtuu poikkeus. Cat-lausetta seuraa final-lohko, joka sisältää lopullisen koodin, joka on taatusti suoritettava riippumatta siitä, mitä try-lohkossa tapahtuu.

Sekä catch-lohko että viimeinen lohko ovat valinnaisia, mutta vähintään yhden niistä on oltava läsnä try-lohkon jälkeen. Kokeile, ota kiinni, ja lopuksi lohkot alkavat ja päättyvät kiharaisiin olkaimiin. Tämä on pakollinen osa syntaksia, eikä sitä voi jättää pois, vaikka välissä olisi vain yksi käsky.

Seuraava katkelma havainnollistaa try/catch/finally -konstruktin syntaksia ja tarkoitusta:

Kokeile ( // Tämä koodi toimii yleensä sujuvasti alusta loppuun. // Mutta jossain vaiheessa se saattaa heittää poikkeuksen // joko suoraan heittokäskyä käyttäen tai epäsuorasti // kutsumalla menetelmää, joka heittää poikkeuksen. ) catch ( ex) ( // Tämän lohkon käskyt suoritetaan jos ja vain jos poikkeus // esiintyy try-lohkossa. Nämä käskyt voivat käyttää paikallista muuttujaa ex, joka // viittaa Error-objektiin tai muuhun heitossa määritettyyn arvoon lauseke // Tämä lohko voi joko käsitellä poikkeuksen jollain tavalla, // jättää sen huomioimatta, kun tekee jotain muuta, tai heittää poikkeuksen uudelleen // käyttämällä throw-lausetta) lopuksi ( // Tämä lohko sisältää lauseita, jotka suoritetaan aina riippumatta. , // mitä try-lohkossa tapahtui Ne suoritetaan, jos try-lohko on suoritettu: // 1) tavanomaiseen tapaan lohkon loppuun // 2) break-, jatka- tai return -käskyn takia. ) poikkeuksella, joka on käsitelty yllä olevassa catch-lohkossa // 4) jääneen poikkeuksen kanssa, joka jatkaa etenemistä // korkeammille tasoille)

Huomaa, että catch-avainsanan jälkeen on tunniste suluissa. Tämä tunniste on samanlainen kuin funktioparametri. Kun poikkeus havaitaan, tämä parametri määritetään poikkeukselle (esimerkiksi Error-objektille). Toisin kuin tavallinen muuttuja, catch-lauseeseen liittyvä tunniste on olemassa vain catch-lohkon rungossa.

Seuraava on realistisempi esimerkki try/catch-rakenteesta. Se kutsuu edellisessä esimerkissä määritettyä factorial()-menetelmää ja asiakkaan JavaScript-prompt()- ja alert()-menetelmiä syötteen ja tulosteen järjestämiseksi:

Kokeile ( // Pyydä käyttäjältä lukua var n = Number(prompt("Syötä positiivinen luku", "")); // Laske luvun tekijä, olettaen // että syöte on oikea var f = factorial (n // Tulosta alert(n + "! = " + f) catch (esim.) ( // Jos tiedot ovat virheellisiä, ohjaus siirretään tähän alert(ex); // Ilmoita käyttäjälle virhe )

Jos käyttäjä syöttää negatiivisen luvun, näyttöön tulee varoitusviesti:

Tämä on esimerkki try/catch-konstruktista ilman final-lausetta. Vaikka vihdoin ei käytetä niin usein kuin catch, se on silti hyödyllinen joskus. Lopullisen lohkon suoritus taataan, jos ainakin osa try-lohkosta on suoritettu, riippumatta siitä, kuinka try-lohkossa oleva koodi suoritti suorituksen. Tätä ominaisuutta käytetään yleensä suorittamaan viimeiset toiminnot sen jälkeen, kun koodi on suoritettu kokeilujatkossa.

Normaalitilanteessa ohjaus saavuttaa try-lohkon loppuun ja siirtyy sitten viimeiseen lohkoon, joka suorittaa tarvittavat lopputoiminnot. Jos ohjaus poistuu try-lohkosta return-, jatka- tai break-käskyn seurauksena, lopullinen lohko suoritetaan ennen kuin ohjaus siirretään muualle.

Jos try-lohkossa tapahtuu poikkeus ja sitä käsittelevä catch-lohko on olemassa, ohjaus siirtyy ensin catch-lohkoon ja sitten lopuksi lohkoon. Jos paikallista kiinnityslohkoa ei ole, ohjaus siirtyy ensin viimeiseen lohkoon ja siirtyy sitten lähimpään ulompaan kiinnityslohkoon, joka voi käsitellä poikkeuksen.

Jos lopullinen lohko itse siirtää ohjauksen paluu-, jatka-, tauko- tai heitto-käskyllä ​​tai kutsumalla poikkeuksen heittävää metodia, odottava siirtokomento peruuntuu ja uusi suoritetaan. Jos esimerkiksi lopullinen lohko heittää poikkeuksen, tämä poikkeus korvaa minkä tahansa aiemmin heitetyn poikkeuksen.

Ihmiset ajattelevat, että tietojenkäsittely on taidetta neroille. Todellisuudessa asia on päinvastoin - vain monet ihmiset tekevät asioita, jotka seisovat päällekkäin, kuin tekisivät seinän pienistä kivistä.

Donald Knuth

Olet jo nähnyt kutsuja toimintoihin, kuten hälytys . Funktiot ovat JavaScript-ohjelmoinnin leipä ja voita. Ajatus ohjelman käärimisestä ja sen kutsumisesta muuttujaksi on erittäin suosittu. Se on työkalu suurten ohjelmien jäsentämiseen, toiston vähentämiseen, aliohjelmien nimeämiseen ja aliohjelmien eristämiseen toisistaan.

Ilmeisin funktioiden käyttötapa on uuden sanakirjan luominen. Sanojen keksiminen tavalliselle ihmisproosalle on huono muoto. Tämä on välttämätöntä ohjelmointikielessä.

Keskimääräinen aikuinen venäjänkielinen osaa noin 10 000 sanaa. Harvinainen ohjelmointikieli sisältää 10 000 sisäänrakennettua komentoa. Ja ohjelmointikielen sanasto on selkeämmin määritelty, joten se on vähemmän joustava kuin ihmisen. Siksi meidän on yleensä lisättävä siihen omat sanamme tarpeettoman toiston välttämiseksi.

Funktiomäärittely Funktiomäärittely on normaali muuttujan määritelmä, jossa muuttujan vastaanottama arvo on funktio. Esimerkiksi seuraava koodi määrittelee muuttujan neliön, joka viittaa funktioon, joka laskee tietyn luvun neliön:

Muuttuneen neliö = funktio(x) ( paluu x * x; ); console.log(neliö(12)); // → 144

Funktio luodaan lausekkeella, joka alkaa funktion avainsanalla. Funktioilla on joukko parametreja (tässä tapauksessa vain x) ja runko, joka sisältää käskyt, jotka on suoritettava funktiota kutsuttaessa. Funktion runko on aina suljettu aaltosulkeisiin, vaikka se koostuisi yhdestä lauseesta.

Funktiolla voi olla useita parametreja tai ei niitä ollenkaan. Seuraavassa esimerkissä makeNoise ei sisällä parametriluetteloa, mutta teholla on kaksi:

Muutt makeNoise = function() ( console.log("Paskat!"); ); makeNoise(); // → Khrya! var teho = funktio(kanta, eksponentti) ( var tulos = 1; for (muut count = 0; count< exponent; count++) result *= base; return result; }; console.log(power(2, 10)); // → 1024

Jotkut funktiot palauttavat arvon, kuten teho ja square, toiset eivät, kuten makeNoise, mikä tuottaa vain sivuvaikutuksen. return-käsky määrittää funktion palauttaman arvon. Kun ohjelman käsittely saavuttaa tämän käskyn, se poistuu välittömästi funktiosta ja palauttaa tämän arvon siihen koodiin, josta funktio kutsuttiin. return ilman lauseketta palauttaa määrittelemättömän .

Parametrit ja laajuus Funktioparametrit ovat samoja muuttujia, mutta niiden alkuarvot asetetaan funktiota kutsuttaessa, ei sen koodissa.

Tärkeä funktioiden ominaisuus on, että funktion sisällä luodut muuttujat (mukaan lukien parametrit) ovat paikallisia kyseiselle funktiolle. Tämä tarkoittaa, että tehoesimerkissä tulosmuuttuja luodaan joka kerta kun funktiota kutsutaan, eikä näillä sen yksittäisillä inkarnaatioilla ole mitään tekemistä toistensa kanssa.

Tämä muuttujan sijainti koskee vain funktioissa luotuja parametreja ja muuttujia. Minkä tahansa funktion ulkopuolella määritettyjä muuttujia kutsutaan globaaleiksi, koska ne ovat näkyvissä kaikkialla ohjelmassa. Voit käyttää tällaisia ​​muuttujia myös funktion sisällä, ellet määritä paikallista muuttujaa samalla nimellä.

Seuraava koodi havainnollistaa tätä. Se määrittelee ja kutsuu kaksi funktiota, jotka antavat arvon muuttujalle x. Ensimmäinen ilmoittaa sen paikalliseksi ja muuttaa siten vain paikallista muuttujaa. Toinen ei deklaroi, joten työskentely x:n kanssa funktion sisällä viittaa esimerkin alussa määriteltyyn globaaliin muuttujaan x.

Var x = "ulkopuolella"; var f1 = funktio() ( var x = "f1:n sisällä"; ); f1(); console.log(x); // → ulkopuolella var f2 = function() ( x = "f2:n sisällä"; ); f2(); console.log(x); // → f2:n sisällä

Tämä toiminta auttaa estämään tahattomia vuorovaikutuksia toimintojen välillä. Jos kaikkia muuttujia käytettäisiin missä tahansa ohjelmassa, olisi erittäin vaikeaa varmistaa, että yhtä muuttujaa ei käytetä eri tarkoituksiin. Ja jos käyttäisit muuttujaa uudelleen, kohtaat outoja vaikutuksia, kun kolmannen osapuolen koodi korruptoi muuttujasi arvot. Käsittelemällä funktio-paikallisia muuttujia niin, että ne ovat olemassa vain funktion sisällä, kieli mahdollistaa funktioiden työskentelyn ikään kuin ne olisivat erillisiä pieniä universumeja, jolloin ei tarvitse huolehtia koko koodista.

Sisäkkäinen laajuus JavaScript erottaa enemmän kuin vain globaalien ja paikallisten muuttujien välillä. Toiminnot voidaan määritellä funktioiden sisällä, mikä johtaa useisiin paikallistasoihin.

Esimerkiksi seuraava melko merkityksetön funktio sisältää vielä kaksi sisällä:

Muuttuva maisema = funktio() ( var tulos = ""; var flat = funktio(koko) ( for (muut 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()); // → ___/""""\______/"\_

Tasa- ja vuoristofunktiot näkevät tulosmuuttujan, koska ne ovat sen määrittelevän funktion sisällä. Mutta he eivät näe toistensa lukumuuttujia, koska yhden funktion muuttujat ovat toisen funktion ulkopuolella. Ja maisemafunktion ulkopuolella oleva ympäristö ei näe mitään tämän funktion sisällä määritellyistä muuttujista.

Lyhyesti sanottuna kunkin paikallisen laajuuden sisällä näet kaikki laajuudet, jotka sisältävät sen. Funktiossa käytettävissä olevien muuttujien joukko määräytyy sen sijainnin mukaan, jossa funktio on ilmoitettu ohjelmassa. Kaikki muuttujat funktiomäärittelyä ympäröivistä lohkoista ovat näkyvissä - myös pääohjelman ylimmällä tasolla määritellyt. Tätä lähestymistapaa laajuuksiin kutsutaan leksikaaliseksi.

Ihmiset, jotka ovat opiskelleet muita ohjelmointikieliä, saattavat ajatella, että mikä tahansa kihara aaltosulkeen suljettu lohko luo oman paikallisen ympäristönsä. Mutta JavaScriptissä vain funktiot luovat laajuuden. Voit käyttää vapaasti seisovia lohkoja:

Muuta jotain = 1; ( var something = 2; // Tee jotain jotain muuttujalla... ) // Lohkosta poistui...

Mutta jokin lohkon sisällä on sama muuttuja kuin sen ulkopuolella. Vaikka tällaiset lohkot ovat sallittuja, on järkevää käyttää niitä vain if-lauseisiin ja silmukoihin.

Jos tämä tuntuu sinusta oudolta, et ole ainoa, joka ajattelee niin. JavaScript 1.7 esitteli avainsanan let, joka toimii kuten var, mutta luo muuttujat, jotka ovat paikallisia mille tahansa lohkolle, ei vain funktiolle.

Funktiot arvoina Toimintojen nimiä käytetään yleensä ohjelman nimenä. Tällainen muuttuja asetetaan kerran, eikä se muutu. Joten on helppo sekoittaa funktio ja sen nimi.

Mutta nämä ovat kaksi eri asiaa. Funktiokutsua voidaan käyttää yksinkertaisen muuttujan tavoin - esimerkiksi missä tahansa lausekkeessa. On mahdollista tallentaa funktiokutsu uuteen muuttujaan, siirtää se parametrina toiselle funktiolle ja niin edelleen. Myös funktiokutsun tallentava muuttuja pysyy tavallisena muuttujana ja sen arvoa voidaan muuttaa:

Var launchMissiles = function(arvo) ( missileSystem.launch("tai!"); ); if (safeMode) launchMissiles = function(arvo) (/* peruuta */);

Luvussa 5 käsittelemme upeita asioita, joita voit tehdä välittämällä funktiokutsuja muille funktioille.

Funktioiden ilmoittaminen Lausekkeesta "var square = funktio..." on olemassa lyhyempi versio. Funktioavainsanaa voidaan käyttää lauseen alussa:

Funktio neliö(x) (paluu x * x; )

Tämä on funktion ilmoitus. Lause määrittää neliömuuttujan ja määrittää sille annetun funktion. Toistaiseksi hyvin. Tällaisessa määritelmässä on vain yksi sudenkuoppa.

Console.log("Tulevaisuus sanoo:", future()); function future() ( return "Meillä ei ole vielä lentäviä autoja."; )

Tämä koodi toimii, vaikka toiminto on ilmoitettu sitä käyttävän koodin alapuolella. Tämä johtuu siitä, että funktioilmoitukset eivät ole osa normaalia ylhäältä alas -ohjelman suoritusta. Ne "siirretään" alansa huipulle ja niitä voidaan kutsua millä tahansa kyseisessä laajuudessa olevalla koodilla. Joskus tämä on kätevää, koska voit kirjoittaa koodin järkevimmässä järjestyksessä ilman, että sinun tarvitsee määrittää kaikkia yllä olevia toimintoja, missä niitä käytetään.

Mitä tapahtuu, jos asetamme funktion ilmoituksen ehdollisen lohkon tai silmukan sisään? Sinun ei tarvitse tehdä sitä. Historiallisesti eri JavaScript-käyttöympäristöt ovat käsitelleet tällaisia ​​tapauksia eri tavalla, ja nykyinen kielistandardi kieltää tämän. Jos haluat ohjelmien toimivan peräkkäin, käytä funktiomäärityksiä vain muissa funktioissa tai pääohjelmassa.

Funktio esimerkki() ( funktio a() () // Normaali jos (jotain) ( funktio b() () // Ay-yay-yay! ) )

Call Stack On hyödyllistä tarkastella lähemmin, kuinka suoritusjärjestys toimii funktioiden kanssa. Tässä on yksinkertainen ohjelma muutamalla funktiokutsulla:

Funktio greet(who) ( console.log("Hei, " + kuka); ) greet("Semjon"); console.log("Pokeda");

Se käsitellään jotakuinkin näin: tervehdyksen kutsuminen saa passin hyppäämään funktion alkuun. Se kutsuu sisäänrakennettua console.log-funktiota, joka sieppaa ohjauksen, tekee tehtävänsä ja palauttaa ohjauksen. Sitten hän pääsee tervehtimisen loppuun ja palaa paikkaan, josta häntä kutsuttiin. Seuraava rivi kutsuu uudelleen console.logia.

Tämä voidaan esittää kaavamaisesti näin:

Top greet console.log greet top console.log top

Koska funktion on palattava paikkaan, josta se kutsuttiin, tietokoneen on muistettava konteksti, josta funktio kutsuttiin. Yhdessä tapauksessa console.login pitäisi palata tervehtimään. Toisessa hän palaa ohjelman loppuun.

Paikkaa, jossa tietokone muistaa kontekstin, kutsutaan pinoksi. Joka kerta kun funktiota kutsutaan, nykyinen konteksti työnnetään pinon yläosaan. Kun funktio palaa, se ponnahtaa ylimmän kontekstin pinosta ja käyttää sitä jatkaakseen suorittamista.

Pinon tallennus vaatii muistitilaa. Kun pino kasvaa liian suureksi, tietokone lopettaa suorittamisen ja sanoo jotain kuten "pinon ylivuoto" tai "liian paljon rekursiota". Seuraava koodi osoittaa tämän - se kysyy tietokoneelta erittäin monimutkaisen kysymyksen, joka johtaa loputtomiin hyppyihin kahden toiminnon välillä. Tarkemmin sanottuna se olisi ääretöntä hyppyä, jos tietokoneessa olisi ääretön pino. Todellisuudessa pino vuotaa yli.

Funktio kana() ( return egg(); ) function egg() ( return chicken(); ) console.log(kana() + " tuli ensin."); // → ??

Valinnaiset argumentit Seuraava koodi on täysin laillinen ja toimii ilman ongelmia:

Alert("Hei", "Hyvää iltaa", "Hei kaikille!");

Virallisesti funktiolla on yksi argumentti. Näin haastateltuna hän ei kuitenkaan valita. Hän jättää huomioimatta loput väitteet ja näyttää "Hei".

JavaScript on hyvin tarkka funktiolle välitettyjen argumenttien määrästä. Jos siirrät liikaa, ylimääräiset jätetään huomiotta. Liian vähän ja puuttuville annetaan arvo määrittelemätön.

Tämän lähestymistavan haittapuoli on, että on mahdollista - ja jopa todennäköistä - siirtää funktiolle väärä määrä argumentteja ilman, että kukaan valittaa siitä.

Etuna on, että voit luoda funktioita, jotka ottavat valinnaisia ​​argumentteja. Esimerkiksi tehofunktion seuraavassa versiossa sitä voidaan kutsua joko kahdella tai yhdellä argumentilla - jälkimmäisessä tapauksessa eksponentti on yhtä suuri kuin kaksi ja funktio toimii kuin neliö.

Funktioteho(kanta, eksponentti) ( if (eksponentti == määrittelemätön) eksponentti = 2; var tulos = 1; for (var count = 0; count< exponent; count++) result *= base; return result; } console.log(power(4)); // → 16 console.log(power(4, 3)); // → 64

Seuraavassa luvussa nähdään, kuinka voit selvittää funktion rungosta sille välitettyjen argumenttien tarkan määrän. Tämä on hyödyllistä, koska... voit luoda funktion, joka ottaa minkä tahansa määrän argumentteja. Esimerkiksi console.log käyttää tätä ominaisuutta ja tulostaa kaikki sille välitetyt argumentit:

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

Sulkemiset Kyky käyttää funktiokutsuja muuttujina yhdistettynä siihen, että paikalliset muuttujat luodaan uudelleen joka kerta kun funktiota kutsutaan, johtaa meidät mielenkiintoiseen kysymykseen. Mitä tapahtuu paikallisille muuttujille, kun funktio lakkaa toimimasta?

Seuraava esimerkki havainnollistaa tätä ongelmaa. Se ilmoittaa wrapValue-funktion, joka luo paikallisen muuttujan. Sitten se palauttaa funktion, joka lukee tämän paikallisen muuttujan ja palauttaa sen arvon.

Funktio wrapValue(n) ( var localVariable = n; return function() ( return localVariable; ); ) var wrap1 = wrapValue(1); var wrap2 = wrapArvo(2); konsoli.log(wrap1()); // → 1 konsoli.log(wrap2()); // → 2

Tämä on pätevä ja toimii kuten pitääkin - pääsy muuttujaan säilyy. Lisäksi saman muuttujan useita esiintymiä voi esiintyä samanaikaisesti, mikä vahvistaa entisestään sitä tosiasiaa, että paikalliset muuttujat luodaan uudelleen jokaisen funktiokutsun yhteydessä.

Tätä kykyä toimia viittauksen kanssa paikallisen muuttujan esiintymään kutsutaan sulkemiseksi. Funktiota, joka sulkee paikalliset muuttujat, kutsutaan sulkemiseksi. Se ei ainoastaan ​​vapauta sinua murehtimasta muuttuvista käyttöioista, vaan sen avulla voit myös käyttää toimintoja luovasti.

Pienellä muutoksella teemme esimerkistämme funktion, joka kertoo numerot millä tahansa annetulla luvulla.

Funktiokerroin(kerroin) ( paluufunktio(luku) ( paluuluku * tekijä; ); ) var double = kerroin(2); console.log(twice(5)); // → 10

Erillistä muuttujaa, kuten localVariable wrapValue-esimerkistä, ei enää tarvita. Koska parametri itsessään on paikallinen muuttuja.

Vaatii harjoittelua, että alkaa ajatella tällä tavalla. Hyvä mentaalinen malli on kuvitella, että funktio jäädyttää koodin kehoonsa ja kääriä sen pakkaukseen. Kun näet palautustoiminnon (...) (...), ajattele sitä ohjauspaneelina koodinpalalle, joka on jäädytetty myöhempää käyttöä varten.

Esimerkissämme kerroin palauttaa jäädytetyn koodinpätkän, jonka tallennamme kaksinkertaiseen muuttujaan. Viimeinen rivi kutsuu muuttujan sisältämää funktiota, mikä saa tallennetun koodin aktivoitumaan (palautusnumero * kerroin;). Sillä on edelleen pääsy kerroinmuuttujaan, joka määritettiin kutsuttaessa kerrointa, ja sillä on myös pääsy sulatuksen aikana välitettyyn argumenttiin (5) numeerisena parametrina.

Rekursio Funktio voi hyvinkin kutsua itseään, kunhan se huolehtii, ettei se vuoda pinon yli. Tätä funktiota kutsutaan rekursiiviseksi. Tässä on esimerkki vaihtoehtoisesta eksponentioinnista:

Funktio potenssi(kanta, eksponentti) ( jos (eksponentti == 0) palauttaa 1; muuten palauttaa kanta * potenssi(kanta, eksponentti - 1); ) console.log(teho(2, 3)); // → 8

Suunnilleen näin matemaatikot määrittelevät eksponentioinnin, ja ehkä tämä kuvaa käsitettä tyylikkäämmin kuin sykli. Funktio kutsuu itseään useita kertoja eri argumenteilla saavuttaakseen moninkertaisen kertolaskun.

Tässä toteutuksessa on kuitenkin ongelma - tavallisessa JavaScript-ympäristössä se on 10 kertaa hitaampi kuin silmukalla varustettu versio. Silmukan läpi kulkeminen on halvempaa kuin funktion kutsuminen.

Nopeus vs. eleganssi dilemma on varsin mielenkiintoinen. Ihmisten mukavuuden ja koneiden mukavuuden välillä on tietty ero. Mitä tahansa ohjelmaa voidaan nopeuttaa tekemällä siitä suurempi ja monimutkaisempi. Ohjelmoijan on löydettävä sopiva tasapaino.

Ensimmäisen eksponentioinnin tapauksessa epäelegantti silmukka on melko yksinkertainen ja suoraviivainen. Ei ole järkevää korvata sitä rekursiolla. Usein ohjelmat kuitenkin käsittelevät niin monimutkaisia ​​käsitteitä, että tehokkuutta halutaan vähentää lisäämällä luettavuutta.

Perussääntö, joka on toistettu useammin kuin kerran ja jonka kanssa olen täysin samaa mieltä, ei ole huolehtia suorituskyvystä ennen kuin olet täysin varma, että ohjelma hidastuu. Jos näin on, etsi osat, jotka kestävät pisimpään ja vaihda eleganssia tehokkuuteen siellä.

Emme tietenkään saisi heti täysin sivuuttaa suorituskykyä. Monissa tapauksissa, kuten eksponentioinnissa, emme saa paljon yksinkertaisuutta tyylikkäistä ratkaisuista. Joskus kokenut ohjelmoija huomaa heti, että yksinkertainen lähestymistapa ei koskaan ole tarpeeksi nopea.

Korostan tätä, koska liian monet aloittelevat ohjelmoijat ovat pakkomielle tehokkuudesta pienissäkin asioissa. Tulos on suurempi, monimutkaisempi ja usein virheettömät. Tällaisten ohjelmien kirjoittaminen kestää kauemmin, mutta ne eivät usein toimi paljon nopeammin.

Mutta rekursio ei aina ole vain vähemmän tehokas vaihtoehto silmukoille. Jotkut ongelmat on helpompi ratkaista rekursiolla. Useimmiten tämä on useiden puun oksien läpikulku, joista jokainen voi haarautua.

Tässä on arvoitus: voit saada äärettömän määrän lukuja aloittamalla numerolla 1 ja sitten joko lisäämällä 5 tai kertomalla 3:lla. Kuinka kirjoitetaan funktio, joka yrittää löytää yhteen- ja kertolaskujen sarjan luvun annettuna. jotka johtavat tiettyyn numeroon? Esimerkiksi luku 13 voidaan saada kertomalla ensin 1 kolmella ja lisäämällä sitten 5 kahdesti. Ja numeroa 15 ei voi saada tällä tavalla ollenkaan.

Rekursiivinen ratkaisu:

Funktio findSolution(target) ( funktio find(aloitus, historia) ( if (aloitus == kohde) paluuhistoria; else if (aloitus > kohde) return null; else return find(aloitus + 5, "(" + historia + " + 5)") || find(aloitus * 3, "(" + historia + " * 3)"); ) return find(1, "1"); ) console.log(findSolution(24)); // → (((1 * 3) + 5) * 3)

Tämä esimerkki ei välttämättä löydä lyhintä ratkaisua - se tyydyttää mikä tahansa. En odota sinun ymmärtävän heti, miten ohjelma toimii. Mutta ymmärretään tämä loistava harjoitus rekursiivisessa ajattelussa.

Sisäinen funktiohaku suorittaa rekursiota. Se vaatii kaksi argumenttia - nykyisen numeron ja merkkijonon, joka sisältää tietueen siitä, kuinka olemme päässeet tähän numeroon. Ja se palauttaa joko merkkijonon, joka näyttää vaihesarjamme, tai nollan.

Tätä varten toiminto suorittaa yhden kolmesta toiminnosta. Jos annettu luku on yhtä suuri kuin tavoite, niin nykyinen tarina on juuri tapa saavuttaa se, joten se palaa. Jos annettu luku on suurempi kuin tavoite, ei ole mitään järkeä jatkaa kertomista ja yhteenlaskua, koska se vain kasvaa. Ja jos emme ole vielä saavuttaneet tavoitetta, funktio kokeilee molempia mahdollisia polkuja alkaen annetusta numerosta. Hän kutsuu itsensä kahdesti, kerran kummallakin menetelmällä. Jos ensimmäinen kutsu ei palauta tyhjää, se palautetaan. Toisessa tapauksessa toinen palautetaan.

Ymmärtääksemme paremmin, kuinka toiminto saavuttaa halutun vaikutuksensa, katsotaanpa sen soittamia kutsuja löytääkseen ratkaisun numeroon 13.

Etsi(1, "1") etsi(6, "(1 + 5)") etsi(11, "((1 + 5) + 5)") etsi(16, "((1 + 5) + 5 ) + 5)") liian suuri löytö(33, "((1 + 5) + 5) * 3)") liian suuri löytö(18, "((1 + 5) * 3)") liian suuri löytö( 3, "(1 * 3)") etsi(8, "((1 * 3) + 5)") etsi(13, "((1 * 3) + 5) + 5)") löydetty!

Sisennys näyttää puhelupinon syvyyden. Ensimmäisellä kerralla hakutoiminto kutsuu itseään kahdesti tarkistaakseen (1 + 5) ja (1 * 3) alkavat ratkaisut. Ensimmäinen kutsu etsii ratkaisua, joka alkaa (1 + 5) ja tarkistaa rekursion avulla kaikki ratkaisut, jotka tuottavat luvun, joka on pienempi tai yhtä suuri kuin vaadittu luku. Ei löydä sitä ja palauttaa nollan. Sitten operaattori || ja siirtyy funktiokutsuun, joka tutkii vaihtoehtoa (1 * 3). Meillä on onnea tässä, sillä kolmannessa rekursiivisessa kutsussa saamme 13. Tämä puhelu palauttaa merkkijonon, ja jokainen || matkan varrella se ohittaa tämän linjan korkeammalle, mikä palauttaa ratkaisun.

Kasvavat funktiot On olemassa kaksi enemmän tai vähemmän luonnollista tapaa lisätä funktioita ohjelmaan.

Ensimmäinen on, että kirjoitat samanlaisen koodin useita kertoja. Tätä tulisi välttää - enemmän koodia tarkoittaa enemmän tilaa virheille ja enemmän luettavaa niille, jotka yrittävät ymmärtää ohjelmaa. Otamme siis toistuvan toiminnon, annamme sille hyvän nimen ja laitamme sen funktioksi.

Toinen tapa on, että huomaat tarpeen uudelle toiminnallisuudelle, joka kannattaa sijoittaa erilliseen toimintoon. Aloitat funktion nimellä ja kirjoitat sitten sen rungon. Voit jopa aloittaa kirjoittamalla funktiota käyttävän koodin ennen kuin itse funktio on määritelty.

Se, kuinka vaikeaa sinun on nimetä toiminto, osoittaa, kuinka hyvin ymmärrät sen toiminnallisuuden. Otetaan esimerkki. Meidän on kirjoitettava ohjelma, joka tulostaa kaksi numeroa, tilalla olevien lehmien ja kanojen lukumäärän, joita seuraa sanat "lehmät" ja "kanat". Sinun on lisättävä nollia edessä oleviin numeroihin niin, että jokainen on täsmälleen kolmella paikalla.

007 Lehmät 011 Kanat

Ilmeisesti tarvitsemme funktion, jossa on kaksi argumenttia. Aloitetaan koodaaminen.
// tulosta FarmInventory-funktio printFarmInventory(lehmät, kanat) ( var cowString = String(lehmät); while (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);

Jos lisäämme merkkijonoon .length, saamme sen pituuden. Osoittautuu, että while-silmukat lisäävät numeroihin etunollia, kunnes ne saavat kolmen merkin rivin.

Valmis! Mutta juuri kun olimme lähettämässä koodia maanviljelijälle (mukaan lukien tietysti iso sekki), hän soittaa ja kertoo, että hänen tilallaan on sikoja, ja voisimmeko lisätä sikojen lukumäärän näytön ohjelmoida?

Tietysti se on mahdollista. Mutta kun alamme kopioida ja liittää koodia näiltä neljältä riviltä, ​​ymmärrämme, että meidän täytyy pysähtyä ja ajatella. Täytyy olla parempi tapa. Yritämme parantaa ohjelmaa:

// tuloste lisäämällä nollia JA tarroja -funktio printZeroPaddedWithLabel(numero, etiketti) ( var numberString = Merkkijono(numero); 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);

Toimii! Mutta nimi printZeroPaddedWithLabel on hieman outo. Se yhdistää kolme asiaa – tulostuksen, nollien lisäämisen ja nimiön – yhdeksi funktioksi. Sen sijaan, että lisäisit kokonaisen toistuvan fragmentin funktioon, korostetaan yksi käsite:

// lisää nollafunktio zeroPad(numero, leveys) ( var string = String(numero); while (merkkijono.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);

Funktio, jolla on mukava, selkeä nimi zeroPad, tekee koodista helpompi ymmärtää. Ja sitä voidaan käyttää monissa tilanteissa, ei vain meidän tapauksessamme. Esimerkiksi muotoiltujen taulukoiden näyttämiseen numeroineen.

Kuinka älykkäitä ja monipuolisia ominaisuuksien tulee olla? Voimme kirjoittaa yksinkertaisen funktion, joka täydentää numeron nollia enintään kolmeen paikkaan, tai hienostuneen yleiskäyttöisen funktion lukujen muotoiluun, joka tukee murtolukuja, negatiivisia lukuja, pisteiden tasausta, täyttöä jne.

Hyvä nyrkkisääntö on lisätä vain toimintoja, joista tiedät olevan hyötyä. Joskus on houkuttelevaa luoda yleiskäyttöisiä puitteita jokaiseen pieneen tarpeeseen. Vastusta häntä. Et koskaan lopeta työtä, päädyt vain kirjoittamaan joukon koodia, jota kukaan ei käytä.

Toiminnot ja sivuvaikutukset Toiminnot voidaan karkeasti jakaa niihin, joita kutsutaan sivuvaikutustensa vuoksi, ja niihin, joita kutsutaan jonkin arvon saavuttamiseksi. Tietenkin on myös mahdollista yhdistää nämä ominaisuudet yhdeksi funktioksi.

Maatilaesimerkin ensimmäinen aputoiminto, printZeroPaddedWithLabel, kutsutaan, koska sillä on sivuvaikutus: se tulostaa merkkijonon. Toinen, zeroPad, palautusarvon takia. Eikä ole sattumaa, että toinen toiminto on hyödyllinen useammin kuin ensimmäinen. Arvoja palauttavia toimintoja on helpompi yhdistää toisiinsa kuin sivuvaikutuksia tuottavia toimintoja.

Puhdas funktio on erityinen arvon palauttava funktio, jolla ei vain ole sivuvaikutuksia, mutta se ei myöskään ole riippuvainen muun koodin sivuvaikutuksista - se ei esimerkiksi toimi globaalien muuttujien kanssa, jotka voivat olla vahingossa muuttunut muualle. Puhdas funktio, kun sitä kutsutaan samoilla argumenteilla, palauttaa saman tuloksen (eikä tee mitään muuta) - mikä on varsin mukavaa. Hänen kanssaan on helppo työskennellä. Kutsu tällaiseen toimintoon voidaan korvata henkisesti sen työn tuloksella muuttamatta koodin merkitystä. Kun haluat testata tällaista funktiota, voit yksinkertaisesti kutsua sitä ja olla varma, että jos se toimii tietyssä kontekstissa, se toimii missä tahansa kontekstissa. Vähemmän puhtaat funktiot voivat tuottaa erilaisia ​​tuloksia monista tekijöistä riippuen, ja niillä voi olla sivuvaikutuksia, joita on vaikea testata ja ottaa huomioon.

Sinun ei kuitenkaan pitäisi hämmentää funktioita, jotka eivät ole täysin puhtaita, tai aloittaa tällaisten funktioiden pyhää koodin puhdistusta. Sivuvaikutukset ovat usein hyödyllisiä. Console.log-funktiosta ei voi kirjoittaa puhdasta versiota, ja tämä toiminto on varsin hyödyllinen. Jotkut toiminnot on helpompi ilmaista sivuvaikutusten avulla.

Yhteenveto Tämä luku osoitti, kuinka voit kirjoittaa omia funktioita. Kun funktion avainsanaa käytetään lausekkeena, se palauttaa osoittimen funktiokutsuun. Kun sitä käytetään käskynä, voit ilmoittaa muuttujan määrittämällä sille funktiokutsun.

Avain toimintojen ymmärtämiseen on paikallinen ulottuvuus. Funktion sisällä ilmoitetut parametrit ja muuttujat ovat sille paikallisia, ne luodaan uudelleen aina, kun sitä kutsutaan, eivätkä ne ole näkyvissä ulkopuolelta. Toisen funktion sisällä ilmoitetuilla funktioilla on pääsy sen soveltamisalaan.

On erittäin hyödyllistä erottaa ohjelman suorittamat erilaiset tehtävät funktioiksi. Sinun ei tarvitse toistaa itseäsi funktioiden avulla, jotka tekevät koodista luettavamman jakamalla sen merkityksellisiin osiin, aivan kuten kirjan luvut ja osat auttavat järjestämään tavallista tekstiä.

ExercisesMinimum Edellisessä luvussa mainittiin Math.min-funktio, joka palauttaa pienimmän argumenttinsa. Nyt voimme kirjoittaa sellaisen funktion itse. Kirjoita min-funktio, joka ottaa kaksi argumenttia ja palauttaa niistä minimin.

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

Rekursio Olemme nähneet, että % (modulo) -operaattorilla voidaan määrittää, onko luku (%2) parillinen. Tässä on toinen tapa määritellä se:

Nolla on parillinen.
Yksikkö on outo.
Millä tahansa luvulla N on sama pariteetti kuin N-2:lla.

Kirjoita rekursiivinen funktio onEven näiden sääntöjen mukaan. Sen on hyväksyttävä luku ja palautettava looginen arvo.

Testaa sitä arvoilla 50 ja 75. Anna sille -1. Miksi hän toimii näin? Onko mahdollista korjata jotenkin?

Testaa sitä 50:llä ja 75:llä. Katso kuinka se toimii -1:llä. Miksi? Voitko ajatella tapaa korjata tämä?

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

Pavujen laskeminen.

Merkkijonon merkkinumero N saadaan lisäämällä siihen .charAt(N) ("string".charAt(5)) - samalla tavalla kuin merkkijonon pituus .lengthillä. Palautusarvo on merkkijono, joka koostuu yhdestä merkistä (esimerkiksi "k"). Merkkijonon ensimmäisen merkin paikka on 0, mikä tarkoittaa, että viimeisen merkin sijainti string.length - 1. Toisin sanoen kahden merkin merkkijonon pituus on 2 ja sen merkkipaikat ovat 0 ja 1.

Kirjoita funktio countBs, joka ottaa merkkijonon argumenttina ja palauttaa merkkijonon sisältämien B-merkkien määrän.

Kirjoita sitten funktio nimeltä countChar, joka toimii kuten countBs, mutta ottaa toisen parametrin - merkin, jota etsimme merkkijonosta (sen sijaan, että laskettaisiin vain "B"-merkkien lukumäärä). Voit tehdä tämän muokkaamalla countBs-funktiota uudelleen.

Funktiot ovat yksi tärkeimmistä JavaScriptin koodin rakennuspalikoista.

Funktiot koostuvat joukosta komentoja ja suorittavat yleensä yhden tietyn tehtävän (esimerkiksi lukujen summaaminen, juurien laskeminen jne.).

Funktioon sijoitettu koodi suoritetaan vain tämän funktion nimenomaisen kutsun jälkeen.

Toimintoilmoitus

1. Syntaksi:

//Funktion function Functionname(ln1, ln2) (Funktion koodi) määrittely //Funktion Functionname(ln1,lr2) kutsuminen;

2. Syntaksi:

//Funktion var määritys funktion nimi=funktio(ln1, ln2)(Funktion koodi) //Funktion kutsuminen funktion nimi(ln1,lr2);

Functionname määrittää funktion nimen. Jokaisella sivun funktiolla on oltava yksilöllinen nimi. Toiminnon nimi on määritettävä latinalaisin kirjaimin, eikä se saa alkaa numeroilla.

ln1 ja ln2 ovat muuttujia tai arvoja, jotka voidaan siirtää funktioon. Kullekin funktiolle voidaan välittää rajoittamaton määrä muuttujia.

Huomaa: vaikka funktiolle ei välitetä muuttujia, älä unohda lisätä sulkuja "()" funktion nimen perään.

Huomaa, että JavaScriptin funktioiden nimet ovat kirjainkoolla.

Esimerkki JavaScript-funktiosta

Alla olevan esimerkin messageWrite()-toiminto suoritetaan vasta painikkeen napsautuksen jälkeen.

Huomaa, että tämä esimerkki käyttää onclick-tapahtumaa. JavaScript-tapahtumia käsitellään yksityiskohtaisesti myöhemmin tässä opetusohjelmassa.

// Funktio kirjoittaa tekstiä sivufunktioon messageWrite() ( document.write("Tämä teksti kirjoitettiin sivulle JavaScriptillä!"); )

Muuttujien välittäminen funktioille

Voit välittää funktioille rajattoman määrän muuttujia.

Huomaa: kaikki funktioiden sisällä olevien muuttujien käsittelyt eivät itse asiassa suoriteta itse muuttujia, vaan niiden kopiota, joten itse muuttujien sisältö ei muutu funktioiden suorittamisen seurauksena.

/* Määritellään funktio, joka lisää 10 hyväksyttyyn muuttujaan ja näyttää tuloksen sivulla */ function plus(a)( a=a+10; document.write("Funktion tulos: " + a+"
"); ) var a=25; document.write("Muuttujan arvo ennen funktiokutsua: "+a+"
"); // Kutsu funktio antamalla sille muuttuja plus(a); document.write("Muuttujan arvo funktion kutsun jälkeen: "+a+"
");

Katsaus

Voit käyttää globaalia muuttujaa funktiosta sen kopion sijaan käyttämällä ikkuna.muuttujan_nimi.

Funktio plus(a)(ikkuna.a=a+10; ) var a=25; document.write("Muuttujan arvo ennen funktiokutsua: "+a+"
"); plus(a); document.write("Muuttujan arvo funktion kutsun jälkeen: "+a+"
");

Katsaus

paluu komento

Return-komennolla voit palauttaa arvoja funktioista.

//Summafunktio palauttaa sille välitettyjen muuttujien summan funktio sum(v1,v2)( return v1+v2; ) document.write("5+6=" + summa(5,6) + "
"); document.write("10+4=" + summa(10,4) + "
");

Katsaus

Sisäänrakennetut toiminnot

Käyttäjän määrittämien funktioiden lisäksi JavaScriptissä on myös sisäänrakennettuja toimintoja.

Esimerkiksi sisäänrakennetun isFinite-funktion avulla voit tarkistaa, onko välitetty arvo kelvollinen luku.

Document.write(isFinite(40)+"
"); document.write(isFinite(-590)+"
"); document.write(isFinite(90.33)+"
"); document.write(isFinite(NaN)+"
"); document.write(isFinite("Tämä on merkkijono")+"
");

Katsaus

Huomaa: löydät täydellisen luettelon sisäänrakennetuista JavaScript-toiminnoistamme.

Paikalliset ja globaalit muuttujat

Funktioiden sisällä luotuja muuttujia kutsutaan paikallisiksi muuttujiksi. Voit käyttää tällaisia ​​muuttujia vain niissä funktioissa, joissa ne on määritetty.

Kun toimintokoodi on suorittanut suorituksen, tällaiset muuttujat tuhoutuvat. Tämä tarkoittaa, että samannimiset muuttujat voidaan määritellä eri funktioissa.

Toimintokoodin ulkopuolella luotuja muuttujia kutsutaan globaaleiksi muuttujiksi. Näitä muuttujia voidaan käyttää mistä tahansa koodista.

Jos määrität funktion sisällä muuttujan ilman varia, siitä tulee myös globaali.

Globaalit muuttujat tuhoutuvat vasta sivun sulkemisen jälkeen.

//Ilmoita globaalit muuttujat var1 ja var2 var var1="muuttuja1 on olemassa"; var var2; function func1() ( //Määritä var2:lle arvo funktion func1 sisällä var var2="muuttuja on olemassa"; ) //Tulosta toisesta funktiosta muuttujien var1 ja var2 sisältö sivufunktioon func2() ( //Tulosta muuttujan var1 sisältö document.write( var1 + "
"); //Tulosta muuttujan var2 sisältö document.write(muuttuja2); )

Katsaus

Huomaa, että kun se tulostetaan näytölle, var2:n arvo on tyhjä, koska func1 toimii var2:n paikallisessa "versiossa".

Anonyymien toimintojen käyttäminen

Funktioita, jotka eivät sisällä nimeä ilmoitettuna, kutsutaan anonyymeiksi.

Nimettömiä toimintoja ei periaatteessa julisteta kutsuttavaksi myöhemmin koodista kuten tavalliset funktiot, vaan ne välitetään muille funktioille parametreina.

Funktio arrMap(arr,func)( var res=new Array; for (var i=0;i