Funktion kutsuminen javascriptissä. Esimerkki funktion välittämisestä viittauksella. Funktiot muodossa "funktion määritelmälauseke"

  • Käännös

Törmään usein JavaScript-koodiin, joissa virheet johtuvat väärinymmärryksestä funktioiden toiminnasta JavaScriptissä (muuten, suurin osa tästä koodista on kirjoittamani). JavaScript on usean paradigman kieli, ja sillä on mekanismeja toiminnallinen ohjelmointi. On aika tutkia näitä mahdollisuuksia. Tässä artikkelissa kerron sinulle viisi tapaa kutsua toimintoja JavaScriptissä.

JavaScriptin oppimisen alkuvaiheessa aloittelijat yleensä ajattelevat, että sen toiminnot toimivat samalla tavalla kuin esimerkiksi C#:ssa. Mutta JavaScriptin funktioiden kutsumekanismeissa on useita tärkeitä eroja, ja niiden tietämättömyys voi johtaa virheisiin, joita ei ole helppo löytää.

Kirjoitetaan yksinkertainen toiminto, joka palauttaa kolmen elementin taulukon - nykyisen tämän arvon ja kaksi funktiolle välitettyä argumenttia.
funktio makeArray(arg1, arg2)( return [ this, arg1, arg2 ]; )

Yleisin tapa: globaali kutsu Aloittelijat ilmoittavat usein toimintoja yllä olevan esimerkin mukaisesti. Tämän toiminnon kutsuminen on helppoa:
makeArray("yksi", "kaksi"); // => [ ikkuna, "yksi", "kaksi" ]
Odota. Mistä se tuli? ikkunaobjekti? Miksi tämä vastaa ikkunaa?

JavaScriptissä se on aina määritelty riippumatta siitä, suoritetaanko komentosarja selaimessa vai muussa ympäristössä globaali objekti. Mikä tahansa skriptimme koodi, joka ei ole "sidottu" mihinkään (eli objektin määrityksen ulkopuolella), on itse asiassa globaalin objektin yhteydessä. Meidän tapauksessamme makeArray ei ole vain funktio, joka "kävelee" yksinään. Itse asiassa makeArray on globaalin objektin menetelmä (jos koodi suoritetaan selaimessa) . Se on helppo todistaa:
hälytys(ikkunan tyyppi.methodThatDoesntExist); // => määrittelemätön hälytys(ikkunan tyyppi.makeArray); // => funktio
Eli kutsutaan makeArray("one", "two"); vastaa kutsumista window.makeArray("one", "two"); .

Minua harmittaa, että tämä on yleisin tapa kutsua toimintoja, koska se edellyttää globaalin funktion läsnäoloa. Ja me kaikki tiedämme, että globaalit funktiot ja muuttujat eivät ole ohjelmoinnin paras muoto. Tämä pätee erityisesti JavaScriptiin. Vältä globaaleja määritelmiä, etkä tule katumaan sitä.

Funktioiden kutsumissääntö #1: Jos funktiota kutsutaan suoraan, objektia määrittelemättä (esimerkiksi myFunction()), tämän arvo on globaali objekti (ikkuna, jos koodi suoritetaan selaimessa).

Menetelmän kutsuminen Luodaan yksinkertainen objekti ja tehdään makeArray sen menetelmäksi. Ilmoitetaan objekti käyttämällä kirjaimellista merkintää ja kutsutaan sitten menetelmäämme:
// luo objekti var arrayMaker = ( someProperty: "joku arvo", make: makeArray ); // kutsua make()-metodia arrayMaker.make("one", "two"); // => [ arrayMaker, "one", "two" ] // vaihtoehtoinen syntaksi, käytä hakasulkeita arrayMaker["make"]("yksi", "kaksi"); // => [ arrayMaker, "yksi", "kaksi" ]
Näetkö eron? Tämän arvo tässä tapauksessa on itse objekti. Miksi ei ikkunaa, kuten edellisessä tapauksessa, koska funktion määrittely ei ole muuttunut? Salaisuus on, kuinka funktiot välitetään JavaScriptissä. Toiminto on vakiotyyppi JavaScript, joka on itse asiassa objekti, ja kuten kaikki muutkin objektit, toimintoja voidaan välittää ja kopioida. SISÄÄN tässä tapauksessa, kopioimme olennaisesti koko funktion, mukaan lukien argumenttiluettelon ja rungon, ja määritimme tuloksena olevan objektin arrayMaker-objektin make-ominaisuuteen. Tämä vastaa tällaista julistusta:
var arrayMaker = ( someProperty: "Joku arvo"; make: function (arg1, arg2) ( return [ this, arg1, arg2]; ) );
Funktion kutsusääntö #2: Metodikutsun syntaksilla kutsutussa funktiossa, kuten obj.myFunction() tai obj["myFunction"]() , tällä on arvo obj .

Tämän yleisesti yksinkertaisen periaatteen väärinymmärtäminen johtaa usein virheisiin tapahtumien käsittelyssä:
toimintopainikeClicked())( var text = (tämä === ikkuna) ? "ikkuna" : this.id; hälytys(teksti); ) var button1 = document.getElementById("btn1"); var button2 = document.getElementById("btn2"); button1.onclick = painikettaKlikkattiin; button2.onclick = toiminto())( painikettaKlikkattiin(); );
Ensimmäisen painikkeen napsauttaminen näyttää viestin "btn1" koska tässä tapauksessa kutsumme funktiota menetelmänä, ja tämä funktion sisällä saa sen objektin arvon, johon tämä menetelmä kuuluu. Napsauta toista painiketta "ikkuna" koska tässä tapauksessa kutsumme buttonClicked suoraan (eli ei kuten obj.buttonClicked()). Sama asia tapahtuu, kun määritämme tapahtumakäsittelijän elementtitunnisteeseen, kuten kolmannen painikkeen tapauksessa. Kolmannen painikkeen napsauttaminen näyttää saman viestin kuin toinen.

Kun käytät kirjastoja, kuten jQuery, sinun ei tarvitse ajatella tätä. jQuery kirjoittaa tämän arvon uudelleen tapahtumakäsittelijässä siten, että tämä arvo on elementti, joka nosti tapahtuman:
// käytä jQueryä $("#btn1").click(function() ( alert(this.id); // jQuery varmistaa, että "this" on painike ));
Kuinka jQuery onnistuu muuttamaan tämän arvoa? Lue alla.

Kaksi muuta tapaa: apply() ja call() On loogista, että mitä useammin käytät funktioita, sitä useammin sinun on välitettävä ne ja kutsuttava niitä eri yhteyksissä. Usein on tarpeen ohittaa tämän arvo. Jos muistat, JavaScriptin funktiot ovat objekteja. Käytännössä tämä tarkoittaa, että funktioilla on ennalta määrätyt menetelmät. apply() ja call() ovat kaksi niistä. Niiden avulla voit ohittaa tämän arvon:
var auto = ( vuosi: 2008, malli: "Dodge Bailout" ); makeArray.apply(auto, [ "yksi", "kaksi" ]); // => [ auto, "yksi", "kaksi" ] makeArray.call(auto, "yksi", "kaksi"); // => [ auto, "yksi", "kaksi" ]
Nämä kaksi menetelmää ovat hyvin samankaltaisia. Ensimmäinen parametri ohittaa tämän. Niiden väliset erot ovat seuraavissa argumenteissa: Function.apply() hyväksyy joukon arvoja, jotka välitetään funktiolle, kun taas Function.call() hyväksyy argumentit erikseen. Käytännössä mielestäni on kätevämpää käyttää apply() .

Funktion kutsusääntö #3: Jos haluat ohittaa tämän arvon kopioimatta funktiota toiseen objektiin, voit käyttää myFunction.apply(obj) tai myFunction.call(obj) .

Rakentajat En mene yksityiskohtiin mukautettujen tyyppien määrittämisestä JavaScriptissä, mutta mielestäni on tärkeää muistuttaa, että JavaScriptissä ei ole luokkia, ja kaikki mukautetut tyypit tarvitsevat rakentajan. Lisäksi menetelmät mukautettu tyyppi On parempi ilmoittaa se käyttämällä prototyyppiä, joka on konstruktorifunktion ominaisuus. Luodaan oma tyyppimme:
// ilmoittaa konstruktorifunktio ArrayMaker(arg1, arg2) ( this.someProperty = "ei väliä"; this.theArray = [ this, arg1, arg2 ]; ) // ilmoittaa menetelmät ArrayMaker.prototype = ( someMethod: function () ( alert("Jokin menetelmä kutsuu" getArray: function () ( return this.theArray; ) ); var am = new ArrayMaker("yksi", "kaksi"); var other = new ArrayMaker("ensimmäinen", "toinen"); am.getArray(); // => [ am, "yksi", "kaksi" ]
Tässä esimerkissä tärkeä asia on uuden operaattorin läsnäolo ennen funktiokutsua. Jos sitä ei olisi, se olisi globaali kutsu, ja konstruktorissa luodut ominaisuudet kuuluisivat globaaliin objektiin. Emme tarvitse sitä. Lisäksi rakentajat eivät yleensä palauta arvoja eksplisiittisesti. Ilman uutta operaattoria konstruktori palauttaisi undefined , sen kanssa se palauttaa tämän . Sitä pidetään hyvänä tyylinä nimetä rakentajia iso kirjain; Tämä muistuttaa sinua uuden operaattorin tarpeesta.

Muussa tapauksessa rakentajan sisällä oleva koodi on todennäköisesti samanlainen kuin koodi, jonka kirjoittaisit toisella kielellä. Tämän merkitys tässä tapauksessa on uusi kohde, jonka luot.

Funktion kutsusääntö #4: Kun funktiota kutsutaan uudella operaattorilla, tämän arvo on uusi JavaScript-ajonaikaisen objektin luoma objekti. Jos tämä funktio ei palauta mitään objektia eksplisiittisesti, tämä palautetaan implisiittisesti.

Johtopäätös Toivottavasti ymmärrät eron eri tavoilla funktiokutsujen avulla voit parantaa JavaScript-koodiasi. Joskus tähän arvoon liittyviä virheitä on vaikea havaita, joten on järkevää estää ne etukäteen.

Funktiot ovat JavaScriptin avainkäsite. Tärkein ominaisuus kielellä on ensiluokkainen ominaisuustuki (toimii ensiluokkaisena kansalaisena). Mikä tahansa toiminto on objekti, ja siksi sitä voidaan käsitellä objektina, erityisesti:

  • pass argumenttina ja palaa tuloksena kutsuttaessa muita toimintoja (korkeamman asteen funktioita);
  • luoda anonyymisti ja määrittää arvoiksi objektien muuttujille tai ominaisuuksille.

Tämä määrittää JavaScriptin suuren ilmaisuvoiman ja mahdollistaa sen luokittelun yhdeksi funktionaalisen ohjelmoinnin paradigman toteuttavista kielistä (joka itsessään on erittäin siistiä monista syistä).

JavaScriptin funktio on erityinen objekti, jonka avulla voit formalisoida kielen avulla tietyn käyttäytymislogiikan ja tietojenkäsittelyn.

Toimintojen toiminnan ymmärtämiseksi on välttämätöntä (ja riittävää?) ymmärtää seuraavat kohdat:

Funktioiden ilmoittaminen Funktiot muodossa "funktion ilmoituslause"

Toimintoilmoitus ( funktion määritelmä, tai funktion ilmoitus, tai funktiolause) sisältää avainsana toiminto ja seuraavat osat:

  • Toiminnon nimi.
  • Luettelo parametreistä (funktion hyväksymistä), jotka on suljettu suluissa () ja erotettu pilkuilla.
  • Funktiokutsun jälkeen suoritettavat ohjeet on suljettu aaltosulkeisiin ( ).

Esimerkiksi seuraava koodi ilmoittaa yksinkertaisen funktion nimeltä neliö:

Funktio neliö(numero) ( palauttaa numero * numero; )

Neliöfunktio ottaa yhden parametrin nimeltä numero. Se koostuu yhdestä käskystä, mikä tarkoittaa, että palautetaan tämän funktion parametri (tämä on luku) kerrottuna itsellään. Return-lause määrittää arvon, jonka funktio palauttaa.

Palautusnumero * numero;

Primitiiviset parametrit (esimerkiksi numero) välitetään funktiolle arvon mukaan; arvo välitetään funktiolle, mutta jos funktio muuttaa parametrin arvoa, tämä muutos ei heijastu globaalisti tai funktion kutsumisen jälkeen.

Jos annat objektin parametrina (ei esimerkiksi primitiivinä tai käyttäjän määrittämiä objekteja) ja funktio muuttaa sille välitetyn objektin ominaisuutta, tämä muutos näkyy funktion ulkopuolella, kuten seuraavassa näkyy esimerkki:

Funktio myFunc(theObject) ( theObject.make = "Toyota"; ) var mycar = (merkki: "Honda", malli: "Accord", vuosi: 1998); var x, y; x = oma auto.merkki; // x saa arvon "Honda" myFunc(mycar); y = autoni.merkki; // y saa arvon "Toyota" // (funktio muutti ominaisuutta)

Funktiot muodossa "funktion määritelmälauseke"

Funktio muotoa "funktion ilmoituslause" on käsky syntaksissa ( lausunto), toinen funktio voi olla muotoa "funktion määritelmälauseke". Tällainen toiminto voi olla anonyymi (sillä ei ole nimeä). Esimerkiksi neliöfunktiota voitaisiin kutsua näin:

Muuttujan neliö = funktio(numero) (palautusnumero * numero; ); var x = neliö(4); // x saa arvon 16

Nimi voidaan kuitenkin määrittää kutsumaan itseään itse funktiossa ja debuggerille ( virheen korjaaja) tunnistaa funktio pinojäljissä ( pinon jälkiä; "jälki" - "jälki" / "jälki").

Muutt faktoriaali = funktio fac(n) ( paluu n< 2 ? 1: n * fac(n - 1); }; console.log(factorial(3));

Funktiot, jotka ovat muotoa "funktion määritelmälauseke", ovat hyödyllisiä, kun funktio välitetään argumenttina toiselle funktiolle. Seuraava esimerkki näyttää karttafunktion, jonka ensimmäisen argumentin tulee ottaa funktio ja toiseksi taulukko.

Funktiokartta(f, a) ( var tulos = , // Luo uusi taulukko i; for (i = 0; i != a.length; i++) result[i] = f(a[i]); palauta tulos ;)

Seuraavassa koodissa funktiomme ottaa funktion, joka on funktion määritelmälauseke, ja suorittaa sen jokaiselle vastaanotetun taulukon elementille toisena argumenttina.

Funktiokartta(f, a) ( var tulos = ; // Luo uusi taulukko var i; // Ilmoita muuttuja kohteelle (i = 0; i != a.length; i++) result[i] = f(a[i ]); var kuutio = kartta(f,numerot); konsoli.log(kuutio);

Funktio palauttaa: .

SISÄÄN JavaScript-toiminto voidaan ilmoittaa ehdolla. Esimerkiksi seuraava toiminto määritetään vain muuttujalle myFunc, jos num on 0:

Var myFunc; if (num === 0) ( myFunc = function(theObject) ( theObject.make = "Toyota"; ) )

Tässä kuvattujen funktiomäärittelyjen lisäksi voit käyttää Function-konstruktoria myös funktioiden luomiseen merkkijonosta ajon aikana ( suoritusaika), Kuten .

Metodi on funktio, joka on objektin ominaisuus. Voit oppia lisää objekteista ja menetelmistä seuraamalla linkkiä: Objektien kanssa työskentely.

Toimintokutsut

Toiminnon ilmoittaminen ei suorita sitä. Funktiomääritys yksinkertaisesti nimeää funktion ja määrittää, mitä tehdä, kun funktiota kutsutaan. Toimintokutsu itse asiassa suorittaa määritetyt toiminnot määritetyillä parametreilla. Jos esimerkiksi määrität funktion neliön, voit kutsua sitä seuraavasti:

Neliö(5);

Tämä käsky kutsuu funktiota, jonka argumentti on 5. Funktio kutsuu käskyjään ja palauttaa arvon 25.

Funktiot voivat olla laajuudessa, kun ne on jo määritelty, mutta funktiot, jotka ovat muotoa "toimintoilmoituslause" voidaan nostaa ( nostaa - nosto), aivan kuten tässä esimerkissä:

Console.log(neliö(5)); /* ... */ funktio square(n) ( palauttaa n * n; )

Toiminnon laajuus on funktio, jossa se on määritelty, tai koko ohjelma, jos se on ilmoitettu korkeammalla tasolla.

Huomautus: Tämä toimii vain, kun funktion määrittely käyttää yllä olevaa syntaksia (eli funktiota funcName()). Alla oleva koodi ei toimi. Tämä tarkoittaa, että funktion nosto toimii vain funktion määrittelyn kanssa, ei funktiolausekkeen kanssa.

Console.log(neliö); // neliötä korotetaan arvolla määrittelemätön. console.log(neliö(5)); // Tyyppivirhe: neliö ei ole funktio var square = function(n) ( return n * n; )

Funktioargumentit eivät rajoitu merkkijonoihin ja numeroihin. Voit siirtää kokonaisia ​​objekteja funktiolle. Show_props()-funktio (ilmoitettu kohdassa Working with Objects) on esimerkki funktiosta, joka ottaa objektit argumentteina.

Funktio voi kutsua itseään. Esimerkiksi tässä on funktio kertoimen rekursiiviseen laskemiseen:

Funktio factorial(n) ( if ((n === 0) || (n === 1)) palauttaa 1; muuten palauttaa (n * factorial(n - 1)); )

Voit sitten laskea tekijät yhdestä viiteen seuraavasti:

Var a, b, c, d, e; a = tekijä(1); // a saa arvon 1 b = factorial(2); // b saa arvon 2 c = factorial(3); // c saa arvon 6 d = factorial(4); // d saa arvon 24 e = factorial(5); //e saa arvon 120

On muitakin tapoja kutsua funktiota. Usein esiintyy tapauksia, joissa funktioita on kutsuttava dynaamisesti tai funktion argumenttien lukumäärää on muutettava tai funktioon sidottu funktio on kutsuttava erityisessä kontekstissa. Osoittautuu, että funktiot ovat itse objekteja, ja niillä olioilla puolestaan ​​on metodit (katso objekti ). Yksi niistä on menetelmä, jonka avulla tämä tavoite voidaan saavuttaa.

Toiminnan laajuus

(toiminnon laajuus)

Funktiossa ilmoitetut muuttujat eivät ole käytettävissä missään tämän funktion ulkopuolella, joten muuttujat (jotka tarvitaan nimenomaan funktiota varten) ilmoitetaan vain funktion laajuudessa. Tässä tapauksessa funktiolla on pääsy kaikkiin sen soveltamisalaan kuuluviin muuttujiin ja funktioihin. Toisin sanoen globaalissa laajuudessa ilmoitetulla funktiolla on pääsy kaikkiin globaalin laajuuden muuttujiin. Toisen funktion sisällä ilmoitetulla funktiolla on myös pääsy kaikkiin pääfunktionsa muuttujiin ja muihin muuttujiin, joihin tällä pääfunktiolla on pääsy.

// Seuraavat muuttujat on ilmoitettu globaalissa laajuudessa var num1 = 20, num2 = 3, name = "Chamahk"; // Tämä funktio on ilmoitettu globaalissa laajuudessa funktiossa multiply() ( return num1 * num2; ) multiply(); // palauttaa arvon 60 // Esimerkki sisäkkäisestä funktiosta getScore() ( var num1 = 2, num2 = 3; funktio add() ( paluunimi + "pisteytys" + (num1 + num2); ) return add(); ) getScore( ); // palauttaa "Chamahk teki 5"

Laajuus ja toimintopino

(funktiopino)

Rekursio

Funktio voi kutsua itseään. Kolme tapaa kutsua tätä:

  • funktion nimen mukaan
  • funktioon viittaavalla muuttujalla
  • Harkitse esimerkiksi seuraavaa toimintoa:

    Var foo = function bar() ( // lauseet menevät tänne );

    Toiminnon sisällä ( toimintavartalo) kaikki seuraavat puhelut ovat vastaavia:

  • baari()
  • arguments.callee()
  • foo()
  • Itseään kutsuvaa funktiota kutsutaan rekursiivinen funktio (rekursiivinen funktio). Osoittautuu, että rekursio on samanlainen kuin silmukka ( silmukka). Molemmat kutsuvat jotakin koodia useita kertoja, ja molemmat vaativat ehdon (vältettävä loputon silmukka tai pikemminkin ääretön rekursio). Esimerkiksi seuraava silmukka:

    Muutt x = 0; while(x< 10) { // "x < 10" - это условие для цикла // do stuff x++; }

    voitaisiin vaihtaa rekursiivinen funktio ja kutsua tätä funktiota:

    Funktiosilmukka(x) ( jos (x >= 10) // "x >= 10" on suorituksen päättymisen ehto (sama kuin "!(x)< 10)") return; // делать что-то loop(x + 1); // рекурсионный вызов } loop(0);

    Jotkut algoritmit eivät kuitenkaan voi olla yksinkertaisia ​​iteratiivisia silmukoita. Esimerkiksi puurakenteen kaikkien elementtien (esimerkiksi ) saaminen on helpoimmin toteutettavissa käyttämällä rekursiota:

    Funktio walkTree(node) ( if (node== null) // return; // tee jotain elementeillä for (var i = 0; i< node.childNodes.length; i++) { walkTree(node.childNodes[i]); } }

    Silmukkafunktioon verrattuna jokainen rekursiivinen puhelu itsessään aiheuttaa monia rekursiivisia kutsuja.

    Joitakin on myös mahdollista muuttaa rekursiiviset algoritmit ei-rekursiivisiksi, mutta usein niiden logiikka on hyvin monimutkainen ja vaatii pinon ( pino). Itse asiassa rekursio käyttää stach:funktiopinoa.

    Pinon käyttäytyminen" näkyy seuraavassa esimerkissä:

    Funktio foo(i) ( if (i< 0) return; console.log("begin: " + i); foo(i - 1); console.log("end: " + i); } foo(3); // Output: // begin: 3 // begin: 2 // begin: 1 // begin: 0 // end: 0 // end: 1 // end: 2 // end: 3

    Sisäkkäiset toiminnot ja sulkemiset

    Voit sijoittaa yhden toiminnon toisen sisään. Sisäkkäinen funktio ( sisäkkäinen toiminto;sisäinen) yksityinen ( yksityinen) ja se sijoitetaan toiseen funktioon ( ulompi). Näin se muodostuu oikosulku (päättäminen). Sulkeminen on lauseke (yleensä funktio), jolla voi olla vapaita muuttujia, sekä ympäristö, joka sitoo nämä muuttujat (joka "sulkee" "kiinni") ilmaisu).

    Koska sisäkkäinen funktio on sulkeva, tämä tarkoittaa, että sisäkkäinen funktio voi "periä" ( periä) sen funktion argumentteja ja muuttujia, joihin se on sisäkkäin. Toisin sanoen sisäkkäinen funktio sisältää ulomman ( "ulompi") toimintoja.

    Yhteenveto:

    • Sisäkkäinen funktio muodostaa sulkemisen: se voi käyttää ulomman funktion argumentteja ja muuttujia, kun taas ulompi funktio ei voi käyttää sisäkkäisen funktion argumentteja ja muuttujia.

    Seuraava esimerkki näyttää sisäkkäisen funktion:

    Funktio addSquares(a, b) ( funktio neliö(x) ( paluu x * x; ) return square(a) + square(b); ) a = addSquares(2, 3); // palauttaa 13 b = addSquares(3, 4); // palauttaa 25 c = addSquares(4, 5); // palauttaa 41

    Koska sisäkkäinen funktio muodostaa sulkemisen, voit kutsua ulompaa funktiota ja antaa argumentit molemmille funktioille (ulompi ja sisäinen).

    Funktio ulkona(x) (funktio sisällä(y) ( paluu x + y; ) paluu sisälle; ) fn_inside = ulkopuolella(3); // Ajattele sitä: anna minulle funktio // joka välittää 3 result = fn_inside(5); // palauttaa 8 tulos1 = ulkopuolella(3)(5); // palauttaa 8

    Muuttujien tallentaminen

    Huomaa, että x:n arvo säilyi, kun sisäinen palautettiin. Sulkemisen on säilytettävä argumentit ja muuttujat koko laajuudessa. Koska jokainen puhelu tarjoaa mahdollisesti erilaisia ​​argumentteja, jokaiselle ulkopuoliselle kutsulle luodaan uusi sulkeminen. Muisti voidaan tyhjentää vain, kun sisäinen on jo palannut eikä ole enää käytettävissä.

    Tämä ei eroa viitteiden tallentamisesta muihin objekteihin, mutta on usein vähemmän ilmeistä, koska viittauksia ei ole asetettu suoraan eikä niitä voi tarkastella siellä.

    Usein sisäkkäiset funktiot

    Toiminnot voidaan syöttää useita kertoja, esim. toiminto (A) tallentaa toiminnon (B), joka tallentaa toiminnon (C). Sekä funktiot B että C muodostavat sulkemisia, joten B:llä on pääsy A:n muuttujiin ja argumentteihin ja C:llä sama pääsy B:hen. Lisäksi koska C:llä on pääsy B:hen, jolla on sama pääsy A:han, myös C:llä on pääsy samaan. pääsy A. Näin cloures voi tallentaa useita skooppia; ne tallentavat rekursiivisesti sen sisältävien funktioiden laajuuden. Sitä kutsutaan ketjuttaminen (ketju - ketju; Miksi sitä kutsutaan "ketjuttamiseksi" selitetään myöhemmin)

    Harkitse seuraavaa esimerkkiä:

    Funktio A(x) ( funktio B(y) ( funktio C(z) ( konsoli.log(x + y + z); ) C(3); ) B(2); ) A(1); // konsoli näyttää 6 (1 + 2 + 3)

    Tässä esimerkissä C:llä on pääsy funktion B y:ään ja funktion A x:ään. Tämä tapahtuu, koska:

  • Funktio B luo sulkemisen, joka sisältää A:n, ts. B:llä on pääsy funktion A argumentteihin ja muuttujiin.
  • Funktio C luo sulkemisen, joka sisältää B:n.
  • Koska funktion B sulkeminen sisältää A:n, C:n sulkeminen sisältää myös A:n, C:llä on pääsy molempien funktioiden B argumentteihin ja muuttujiin Ja A. Toisin sanoen C sitoutuu ketju (ketju) funktioiden B ja A laajuudet tässä järjestyksessä.
  • Käänteisesti tämä ei kuitenkaan pidä paikkaansa. A:lla ei ole pääsyä C:n muuttujiin ja argumentteihin, koska A:lla ei ole pääsyä B:hen. Näin C pysyy yksityisenä vain B:lle.

    Nimiristiriidat

    Kun sulkemisen laajuuden kahdella argumentilla tai muuttujalla on sama nimi, nimiristiriita (nimiristiriita). Lisää sisäkkäisiä ( enemmän sisäistä) laajuudella on prioriteetti, joten sisäkkäisimmällä laajuudella on korkein prioriteetti ja päinvastoin. Tämä on laajennusketju ( ulottuvuusketju). Aivan ensimmäinen linkki on syvin ulottuvuus ja päinvastoin. Harkitse seuraavaa:

    Function outside() ( var x = 5; function inside(x) ( return x * 2; ) return inside; ) outside())(10); // palauttaa 20 10:n sijaan

    Return x * 2 -käskyssä esiintyi nimiristiriita sisäfunktion parametrin x ja ulkoisen funktion muuttujan x välillä. Scope-ketju on tässä seuraavanlainen: ( sisällä ==> ulkopuolella ==> globaali objekti ( globaali objekti)). Siksi sisäfunktion x on etusijalla ulkoiseen funktioon nähden, ja meille palautetaan 20 (= 10 * 2) eikä 10 (= 5 * 2).

    Sulkemiset

    (Sulkemiset)

    Sulkemiset ovat yksi JavaScriptin pääominaisuuksista. JavaScript sallii funktioiden sisäkkäisyyden ja tarjoaa sisäkkäisiä toimintoja täysi pääsy kaikkiin ulomman funktion sisällä ilmoitettuihin muuttujiin ja funktioihin (ja muihin muuttujiin ja funktioihin, joihin ulkofunktiolla on pääsy).

    Ulkoisella funktiolla ei kuitenkaan ole pääsyä sisäisessä funktiossa ilmoitettuihin muuttujiin ja funktioihin. Tämä tarjoaa eräänlaisen kapseloinnin sisäkkäisen funktion sisällä oleville muuttujille.

    Lisäksi, koska sisäkkäisellä funktiolla on pääsy ulkofunktion laajuuteen, ulkoisessa funktiossa ilmoitetut muuttujat ja funktiot ovat edelleen olemassa sen jälkeen, kun se on suoritettu sisäkkäiselle funktiolle, jos pääsy niihin ja se säilytetään (eli muuttujat, jotka on ilmoitettu ulkoiset toiminnot tallennetaan vain, jos sisäinen toiminto käsittelee niitä).

    Sulkeminen luodaan, kun sisäkkäinen funktio on jotenkin tullut saataville jossain laajuudessa ulkoisen funktion ulkopuolella.

    Var pet = function(name) ( // Ulkofunktio ilmoitti muuttujan "name" var getName = function() ( paluunimi; // Sisäkkäisfunktiolla on pääsy ulkoisen funktion "nimeen" ) return getName; / / Palauta sisäkkäinen funktio, jolloin säilytetään pääsy // siihen toiselle laajuudelle) myPet = pet("Vivie"); lemmikkini(); // "Vivie" palautetaan, // koska jopa ulkoisen funktion suorittamisen jälkeen // nimi säilyy sisäkkäisfunktiolle

    Monimutkaisempi esimerkki on esitetty alla. Objekti, jolla on menetelmät sisäkkäisen funktion manipuloimiseksi ulkofunktiolla, voidaan palauttaa ( palata).

    Var createPet = function(name) ( var sukupuoli; return ( setName: function(newName) ( nimi = newName; ), getName: function() ( return name; ), getSex: function() ( return sex; ), setSex: function(newSex) ( if(typeof newSex === "merkkijono" && (newSex.toLowerCase() === "mies" || newSex.toLowerCase() === "nainen")) (sukupuoli = uusiSukupuoli; ) ) ) ) var lemmikki = createPet("Vivie"); lemmikki.getName(); // Vivie pet.setName("Oliver"); lemmikki.setSex("mies"); lemmikki.getSex(); // uros lemmikki.getName(); // Oliver

    Yllä olevassa koodissa ulomman funktion nimimuuttuja on sisäkkäisen funktion käytettävissä, eikä sisäkkäisiin muuttujiin pääse muulla tavalla kuin sisäkkäisen funktion kautta. Sisäkkäisen funktion sisäkkäiset muuttujat ovat ulkoisten argumenttien ja muuttujien turvallisia varastoja. Ne sisältävät "pysyviä" ja "kapseloituja" tietoja sisäkkäisten funktioiden käsittelemistä varten. Toimintoja ei tarvitse edes määrittää muuttujalle tai niillä ei tarvitse olla nimeä.

    Var getCode = (function() ( var apiCode = "0]Eal(eh&2"; // Koodi, jota emme halua ulkopuolisten pystyvän muokkaamaan... return function() ( return apiCode; ); )()) ; getCode(); // Palauttaa apikoodin

    Sulkimia käytettäessä on kuitenkin otettava huomioon useita sudenkuoppia. Jos yksityinen toiminto määrittää muuttujan, jolla on sama nimi kuin ulomman laajuuden muuttujan nimi, ulkoisen laajuuden muuttujaan ei voi viitata uudelleen.

    Muutt CreatePet = function(name) ( // Ulompi funktio määrittää muuttujan nimeltä "nimi". return ( setName: function(name) ( // Mukana oleva funktio määrittelee myös muuttujan nimeltä "nimi". nimi = nimi; // Miten päästään ulkofunktion määrittelemään "nimeen"?

    Käyttämällä argumenttiobjektia

    Funktion argumenttiobjekti on pseudo-taulukko. Voit viitata funktion sisällä tällaisiin argumentteihin:

    Argumentit[i]

    missä olen sarjanumero argumentti, alkaen 0. Ensimmäinen funktiolle välitetty argumentti otetaan käyttöön argumentteina . Ja saada kaikkien argumenttien lukumäärä - arguments.length .

    Argumentit-objektin avulla voit kutsua funktiota välittämällä sille enemmän argumentteja kuin sen muodollisesti hyväksyttiin. Tämä on erittäin hyödyllistä, jos et tiedä tarkalleen kuinka monta argumenttia funktion tulee ottaa. Voit määrittää funktiolle välitettyjen argumenttien määrän käyttämällä arguments.length-funktiota ja käyttää sitten jokaista argumenttia argumenttiobjektin avulla.

    Harkitse esimerkiksi funktiota, joka ketjuttaa useita merkkijonoja. Ainoa muodollinen argumentti funktiolle on merkkijono, joka määrittää merkit, jotka erottavat ketjutettavat elementit. Toiminto määritellään seuraavasti:

    Funktio myConcat(erotin) ( var tulos = ""; var i; // toista argumenttien (i = 1; i) läpi< arguments.length; i++) { result += arguments[i] + separator; } return result; }

    Voit välittää tälle funktiolle minkä tahansa määrän argumentteja ja se ketjuttaa jokaisen argumentin yhdeksi merkkijonoksi.

    // palauttaa "punainen, oranssi, sininen, " myConcat(", ", "punainen", "oranssi", "sininen"); // palauttaa "norsu; kirahvi; leijona; gepardi; " myConcat("; ", "norsu", "kirahvi", "leijona", "gepardi"); // palauttaa "salvia. basilika. oregano. pippuri. persilja." myConcat(". ", "salvia", "basilika", "oregano", "pippuri", "persilja");

    Koska argumentit on pseudojoukko, joitain taulukkomenetelmiä sovelletaan siihen, esimerkiksi .. in

    Funktio func() ( for (arvo argumenteissa)( console.log(arvo); ) ) func(1, 2, 3); // 1 // 2 // 3

    Huomautus: argumentit on pseudotaulukko, mutta ei taulukko. Tämä on pseudotaulukko, jossa on numeroidut indeksit ja pituusominaisuus. Sillä ei kuitenkaan ole kaikkia taulukkomenetelmiä.

    Lepoparametrit

    Nuolifunktioiden käyttöönottoon vaikutti kaksi tekijää: lyhyemmät funktiot ja tämä sanakirja.

    Lyhyemmät toiminnot

    Jotkut toiminnalliset mallit kannustavat käyttämään lyhyempiä toimintoja. Vertailla:

    Var a = ["Vety", "Helium", "Litium", "Beryllium" ]; var a2 = a.map(funktio(t) ( palauttaa s.pituus; )); konsoli.log(a2); // lokit var a3 = a.map(s => s.length); konsoli.log(a3); // lokit

    Tämä sanasto

    Jopa nuoli toimii kukin uusi ominaisuus määritteli tämän arvon (uusi objekti konstruktorin tapauksessa, määrittelemätön tiukassa tilassa, kontekstiobjekti, jos funktiota kutsutaan objektin menetelmäksi jne.). Tämä osoittautui olio-ohjelmointityylin kannalta ärsyttäväksi.

    Funktio Person() ( // Person()-konstruktori määrittelee `this` itsekseen. this.age = 0; setInterval(function growUp() ( // Ilman tiukkaa tilaa, funktio growUp() määrittelee `this' // globaali objekti , joka on eri kuin `this` // jonka on määrittänyt Person() konstruktori this.age++ ) var p = new Person();

    ECMAScript 3/5:ssä tämä ongelma korjattiin määrittämällä tämän arvo muuttujalle, joka voidaan silmukalla.

    Funktio Person() ( var self = this; // Jotkut ihmiset valitsevat `that` itsen sijaan. // Valitse yksi ja ole johdonmukainen. self.age = 0; setInterval(function growUp() ( // Takaisinsoitto `self`-muuttuja, jonka // arvo on odotettu objekti self.age++), 1000);

    Katso myös Funktio JavaScript-viittauksessa lisäinformaatio objektina toimimisen perusteella.

    Viimeisin päivitys: 09.04.2018

    Toiminnot ovat joukko ohjeita, jotka suorittavat erityistä toimintaa tai tietyn arvon laskeminen.

    Funktiomäärittelyn syntaksi:

    Funktio funktion_nimi([parametri [, ...]])( // Ohjeet )

    Funktiomäärittely alkaa avainsanafunktiolla, jota seuraa funktion nimi. Toiminnon nimi noudattaa samoja sääntöjä kuin muuttujan nimi: se voi sisältää vain numeroita, kirjaimia, alaviivoja ja dollarimerkkejä ($), ja sen on alettava kirjaimella, alaviivalla tai dollarilla.

    Toiminnon nimen jälkeen parametrit on lueteltu suluissa. Vaikka funktiolla ei olisi parametreja, se sisältää vain tyhjiä sulkeita. Sitten sisään aaltosulkeet tulee funktion runko, joka sisältää joukon ohjeita.

    Määritellään yksinkertaisin funktio:

    Funktio display())( document.write("toiminto JavaScriptissä"); )

    Tätä toimintoa kutsutaan näyttö(). Se ei hyväksy mitään parametreja ja se vain kirjoittaa merkkijonon verkkosivulle.

    kuitenkin yksinkertainen määritelmä Ominaisuus ei vielä riitä toimimaan. Sinun täytyy silti soittaa hänelle:

    function display())( document.write("funktio JavaScriptissä"); ) display();

    Funktioille ei tarvitse antaa tiettyä nimeä. Voit käyttää anonyymejä toimintoja:

    Var display = function())( // funktion määritelmä document.write("funktio JavaScriptissä"); ) display();

    Me itse asiassa määritämme näyttömuuttujan ja määritämme sille funktioviitteen. Ja sitten funktiota kutsutaan muuttujan nimen perusteella.

    Voimme myös dynaamisesti määrittää funktioita muuttujalle:

    Funktio goodMorning())( document.write("Hyvää huomenta"); ) function goodEvening())( document.write("Hyvää iltaa"); ) var message = goodHorning; viesti(); // Hyvää huomenta viesti = good Evening; viesti(); // Hyvää iltaa

    Toimintojen parametrit

    Harkitse parametrien välittämistä:

    Function display(x)( // funktion määritelmä var z = x * x; document.write(x + " neliö on yhtä kuin " + z); ) näyttö(5); // funktiokutsu

    Näyttötoiminto ottaa yhden parametrin - x. Siksi funktiota kutsuttaessa voimme välittää sille arvon, esimerkiksi numeron 5, kuten tässä tapauksessa.

    Jos funktio ottaa useita parametreja, niin levitysoperaattorilla... voimme välittää joukon arvoja näille parametreille taulukosta:

    Funktio summa(a, b, c)( olkoon d = a + b + c; konsoli.log(d); ) summa(1, 2, 3); olkoon numerot = ; summa(...numerot);

    Toisessa tapauksessa numerot numerotaulukosta välitetään funktiolle. Mutta jotta taulukkoa ei lähetetä yhtenä arvona, vaan numeroita tästä taulukosta, käytetään hajaoperaattoria (ellipsiä...).

    Valinnaiset parametrit

    Funktiolla voi olla useita parametreja, mutta jotkin tai kaikki parametrit voivat olla valinnaisia. Jos parametreille ei välitetä arvoa, ne ovat oletuksena "määrittämätön".

    Funktio display(x, y)( if(y === määrittelemätön) y = 5; if(x === määrittelemätön) x = 8; olkoon z = x * y; console.log(z); ) display() ; // 40 näyttö(6); // 30 näyttö(6, 4) // 24

    Tässä näyttötoiminto ottaa kaksi parametria. Kun kutsumme funktiota, voimme tarkistaa niiden arvot. Kun funktiota kutsutaan, näiden parametrien arvoja ei kuitenkaan tarvitse välittää. Parametriarvon olemassaolon tarkistamiseksi käytetään vertailua määrittelemättömään arvoon.

    On toinenkin tapa määrittää oletusarvot parametreille:

    Funktio näyttö(x = 5, y = 10)( olkoon z = x * y; console.log(z); ) näyttö(); // 50 näyttö(6); // 60 näyttö(6, 4) // 24

    Jos parametreille x ja y ei välitetä arvoja, ne saadaan numeroiden 5 ja 10 arvoina. Tämä menetelmä on ytimekkäämpi ja intuitiivisempi kuin vertaaminen määrittelemättömään.

    Tässä tapauksessa parametrin oletusarvo voidaan johtaa, joka edustaa lauseketta:

    Toimintojen näyttö(x = 5, y = 10 + x)( olkoon z = x * y; console.log(z); ) näyttö(); // 75 näyttö(6); // 96 näyttö(6, 4) // 24

    Tässä tapauksessa parametrin y arvo riippuu x:n arvosta.

    Tarvittaessa voimme saada kaikki välitetyt parametrit maailmanlaajuisesti saatavilla olevan argumenttitaulukon kautta:

    Funktio display())( var z = 1; for(var i=0; i