Funksjoner i JavaScript. Ekspressiv JavaScript: Funksjoner

Denne artikkelen dekker funksjoner på Javascript-språknivå: opprettelse, parametere, teknikker, nedleggelser og mer.

Opprette funksjoner

Det er 3 måter å lage en funksjon på. Hovedforskjellen i resultatet av arbeidet deres er at en navngitt funksjon er synlig overalt, og en anonym er bare synlig etter erklæringen:

Funksjoner - objekter

I javascript er funksjoner fullverdige objekter av den innebygde funksjonsklassen. Det er derfor de kan tilordnes variabler, sendes rundt, og selvfølgelig har de egenskaper:

Funksjon f() ( ... ) f.test = 6 ... alert(f.test) // 6

Funksjonsegenskaper er også tilgjengelig inne i funksjonen, slik at de kan brukes som statiske variabler.

For eksempel,

Funksjon func() ( var funcObj = arguments.callee funcObj.test++ alert(funcObj.test) ) func.test = 1 func() func()

I begynnelsen av operasjonen oppretter hver funksjon en argumentvariabel i seg selv og tilordner en referanse til seg selv til arguments.callee. Så arguments.callee.test er en egenskap til func.test , dvs. en statisk variabeltest.

I eksemplet var det umulig å lage en oppgave:

Var test = arguments.callee.test test++

siden i dette tilfellet vil ++-operasjonen fungere på den lokale variabeltesten, og ikke på testegenskapen til funksjonsobjektet.

Argumentobjektet inneholder også alle argumentene og kan konverteres til en matrise (selv om det ikke er én), mer om dette nedenfor, i avsnittet om parametere.

omfang

Hver funksjon, eller rettere sagt hver funksjonslansering, setter sitt eget individuelle omfang.

Variabler kan deklareres hvor som helst. Nøkkelordet var spesifiserer en variabel i gjeldende omfang. Hvis du glemmer det, vil variabelen havne i globalt objekt vindu. Uventede skjæringer med andre vindusvariabler, konflikter og feil er mulig.

I motsetning til noen språk, definerer ikke blokker et eget omfang. Det spiller ingen rolle om variabelen er definert innenfor eller utenfor blokken. Så disse to utdragene er helt likeverdige:

En variabel spesifisert via var er synlig overalt i omfanget, selv før var-operatoren. La oss for eksempel lage en funksjon som vil endre variabelen, var for som er nedenfor.

For eksempel:

Funksjon a() ( z = 5 // vil endre z lokalt.. // .. siden z er deklarert via var var z ) // test slette z // slett det globale z a()-varselet(window.z) bare i case // => udefinert, fordi z ble endret lokalt

Funksjonsparametere

Funksjoner kan kjøres med et hvilket som helst antall parametere.

Hvis en funksjon sendes med færre parametere enn i definisjonen, anses de manglende parametrene som udefinerte .

Følgende funksjon returnerer tiden som kreves for å dekke avstanden med en jevn hastighet.

Når den startes for første gang, fungerer funksjonen med argumentene distance=10 , speed=undefined . Vanligvis gir denne situasjonen, hvis den støttes av funksjonen, en standardverdi:

// hvis hastigheten er en falsk verdi (udefinert, 0, usann...) - erstatt 10 hastighet = hastighet || 10

Operatør || i JavaScript returnerer den ikke true/false , men selve verdien (den første som konverteres til true).

Derfor brukes den til å angi standardverdier. I samtalen vår vil hastigheten bli beregnet som udefinert || 10 = 10.

Derfor blir resultatet 10/10 = 1.

Den andre lanseringen er standard.

Den tredje kjøringen spesifiserer flere tilleggsargumenter. Funksjonen gir ikke mulighet til å arbeide med tilleggsargumenter, så de blir ganske enkelt ignorert.

Vel, i det siste tilfellet er det ingen argumenter i det hele tatt, så avstand = udefinert , og vi har resultatet av divisjon udefinert/10 = NaN (Not-A-Number, en feil oppstod).

Arbeide med et ubestemt antall parametere

Umiddelbart før man går inn i funksjonskroppen, opprettes det automatisk et arguments-objekt, som inneholder

  • Anropsargumenter, starter fra null
  • Lengde i lengdeegenskapen
  • En lenke til selve funksjonen i callee-egenskapen
  • For eksempel,

    Funksjon func() ( for(var i=0;i alert(3)

    Eksempel på å sende en funksjon ved referanse

    En funksjon kan enkelt overføres som et argument til en annen funksjon.

    For eksempel tar map funksjonen func, bruker den på hvert element i array arr, og returnerer den resulterende arrayen:

    Var map = function(func, arr) ( var resultat = for(var i=0; i [ vindu, "en", "to" ]
    Vente. Hvor kommer vindusobjektet fra? Hvorfor er dette lik vindu?

    I JavaScript, uansett om skriptet kjøres i nettleseren eller i et annet miljø, er det alltid definert globalt objekt. Enhver kode i skriptet vårt som ikke er "bundet" til noe (det vil si utenfor objektdeklarasjonen) er faktisk i konteksten til det globale objektet. I vårt tilfelle er makeArray ikke bare en funksjon som "går" alene. Faktisk er makeArray en metode for det globale objektet (i tilfelle kodeutførelse i nettleseren) vinduet . Det er lett å bevise:
    alert(type vindu.metode som ikke eksisterer); // => udefinert varsel(typevindu.makeArray); // => funksjon
    Det vil si å kalle makeArray("one", "to"); tilsvarer å kalle window.makeArray("one", "to"); .

    Det gjør meg trist at dette er den vanligste måten å kalle funksjoner på, fordi det innebærer tilstedeværelsen av en global funksjon. Og vi vet alle at globale funksjoner og variabler ikke er den beste formen innen programmering. Dette gjelder spesielt for JavaScript. Unngå globale definisjoner, og du vil ikke angre på det.

    Funksjonsanropsregel #1: Hvis en funksjon kalles direkte, uten å spesifisere et objekt (for eksempel myFunction()), vil verdien av dette være det globale objektet (vinduet hvis koden kjøres i nettleseren).

    Kalle en metode La oss lage et enkelt objekt og gjøre makeArray til metoden. La oss erklære objektet ved å bruke bokstavelig notasjon, og deretter kalle metoden vår:
    // opprette et objekt var arrayMaker = ( someProperty: "noen verdi", make: makeArray ); // kaller make()-metoden arrayMaker.make("one", "to"); // => [ arrayMaker, "one", "to" ] // alternativ syntaks, bruk firkantede parenteser arrayMaker["make"]("one", "to"); // => [ arrayMaker, "en", "to" ]
    Ser du forskjellen? Verdien av dette i dette tilfellet er selve objektet. Hvorfor ikke vinduet , som i forrige tilfelle, siden funksjonsdeklarasjonen ikke er endret? Hemmeligheten er hvordan funksjoner sendes i JavaScript. Funksjonen er standard type JavaScript, som faktisk er et objekt, og som alle andre objekter, kan funksjoner sendes og kopieres. I i dette tilfellet, kopierte vi i hovedsak hele funksjonen, inkludert argumentlisten og kroppen, og tildelte det resulterende objektet til arrayMaker-objektets make-egenskap. Dette tilsvarer en erklæring som dette:
    var arrayMaker = ( someProperty: "Noen verdi"; make: function (arg1, arg2) (retur [dette, arg1, arg2]; ) );
    Funksjonsanropsregel #2: I en funksjon som kalles ved å bruke metodekallsyntaks, for eksempel obj.myFunction() eller obj["myFunction"]() , vil denne ha verdien obj .

    Misforståelse av dette generelt enkle prinsippet fører ofte til feil ved behandling av hendelser:
    function buttonClicked())( var text = (dette === vinduet) ? "window" : this.id; alert(text); ) var button1 = document.getElementById("btn1"); var button2 = document.getElementById("btn2"); button1.onclick = buttonClicked; button2.onclick = function())( buttonClicked(); );
    Ved å klikke på den første knappen vises en melding "btn1" fordi vi i dette tilfellet kaller en funksjon som en metode, og denne inne i funksjonen vil få verdien av objektet som denne metoden tilhører. Klikk på den andre knappen vil gi "vindu" fordi vi i dette tilfellet kaller buttonClicked direkte (dvs. ikke som obj.buttonClicked()). Det samme skjer når vi tilordner en hendelsesbehandler til elementtaggen, som i tilfellet med den tredje knappen. Hvis du klikker på den tredje knappen, vises den samme meldingen som den andre.

    Når du bruker biblioteker som jQuery, trenger du ikke tenke på dette. jQuery vil passe på å omskrive denne verdien i hendelsesbehandleren slik at denne verdien er elementet som utløste hendelsen:
    // bruk jQuery $("#btn1").click(function() ( alert(this.id); // jQuery vil sørge for at "dette" er en knapp ));
    Hvordan klarer jQuery å endre verdien på dette? Les under.

    To måter til: application() og call() Det er logisk at jo oftere du bruker funksjoner, desto oftere må du sende dem og kalle dem i forskjellige sammenhenger. Ofte er det behov for å overstyre verdien av dette. Hvis du husker, er funksjoner i JavaScript objekter. I praksis betyr dette at funksjoner har forhåndsdefinerte metoder. application() og call() er to av dem. De lar deg overstyre denne verdien:
    var bil = (år: 2008, modell: "Dodge Bailout" ); makeArray.apply(bil, [ "en", "to" ]); // => [ bil, "en", "to" ] makeArray.call(bil, "en", "to"); // => [ bil, "en", "to" ]
    Disse to metodene er veldig like. Den første parameteren overstyrer dette. Forskjellene mellom dem er i de påfølgende argumentene: Function.apply() aksepterer en rekke verdier som sendes til funksjonen, mens Function.call() godtar argumentene separat. I praksis er det etter min mening mer praktisk å bruke application() .

    Funksjonsanropsregel #3: Hvis du vil overstyre verdien av denne uten å kopiere funksjonen til et annet objekt, kan du bruke myFunction.apply(obj) eller myFunction.call(obj) .

    Konstruktører Jeg vil ikke gå i detalj om å deklarere tilpassede typer i JavaScript, men jeg tror det er viktig å minne deg på at det ikke finnes klasser i JavaScript, og enhver tilpasset type trenger en konstruktør. I tillegg er det bedre å deklarere metoder av en tilpasset type ved å bruke prototype , som er en egenskap for konstruktørfunksjonen. La oss lage vår egen type:
    // erklære konstruktørfunksjonen ArrayMaker(arg1, arg2) ( this.someProperty = "uansett"; this.theArray = [ this, arg1, arg2 ]; ) // erklære metoder ArrayMaker.prototype = ( someMethod: function () ( alert( "Called by someMethod"); ), getArray: function () ( return this.theArray; ) ); var am = new ArrayMaker("one", "to"); var other = new ArrayMaker("første", "andre"); am.getArray(); // => [ am, "en", "to" ]
    Det viktige i dette eksemplet er tilstedeværelsen av den nye operatøren før funksjonsanropet. Hvis det ikke var for det, ville det vært et globalt kall, og egenskapene som ble opprettet i konstruktøren ville tilhørt det globale objektet. Det trenger vi ikke. I tillegg returnerer konstruktører vanligvis ikke verdier eksplisitt. Uten den nye operatøren ville konstruktøren returnert udefinert, med den returnerer den dette. God stil navnene på konstruktørene vurderes stor bokstav; Dette vil minne deg på behovet for den nye operatøren.

    Ellers vil koden inne i konstruktøren sannsynligvis være lik koden du ville skrevet på et annet språk. Verdien av dette i dette tilfellet er det nye objektet du oppretter.

    Funksjonsanropsregel nr. 4: Ved oppkalling av en funksjon med operatør ny, vil verdien av dette være et nytt objekt opprettet av JavaScript-runtime. Hvis denne funksjonen ikke returnerer noe objekt eksplisitt, vil dette bli returnert implisitt.

    Konklusjon Forhåpentligvis forstå forskjellen mellom forskjellige måter funksjonskall lar deg forbedre JavaScript-koden din. Noen ganger er feil knyttet til denne verdien vanskelig å fange, så det er fornuftig å forhindre dem på forhånd.

    Funksjoner er et nøkkelbegrep i JavaScript. Den viktigste funksjonen språk har førsteklasses funksjonsstøtte (fungerer som førsteklasses borger). Enhver funksjon er et objekt, og derfor kan den manipuleres som et objekt, spesielt:

    • pass som et argument og returner som et resultat når du kaller andre funksjoner (funksjoner av høyere orden);
    • opprette anonymt og tilordne som verdier til variabler eller egenskaper til objekter.

    Dette bestemmer den høye uttrykkskraften til JavaScript og lar det klassifiseres som et av språkene som implementerer det funksjonelle programmeringsparadigmet (som i seg selv er veldig kult av mange grunner).

    En funksjon i JavaScript er en spesiell type objekt som lar deg formalisere ved hjelp av språket en viss logikk for atferd og databehandling.

    For å forstå hvordan funksjoner fungerer, er det nødvendig (og tilstrekkelig?) å ha forståelse for følgende punkter:

    Erklære funksjoner Funksjoner av skjemaet "funksjonserklæring"

    Funksjonserklæring ( funksjonsdefinisjon, eller funksjonserklæring, eller funksjonsuttalelse) består av funksjonsnøkkelordet og følgende deler:

    • Funksjonsnavn.
    • En liste over parametere (godkjent av funksjonen) omsluttet av parenteser () og atskilt med komma.
    • Instruksjonene som vil bli utført etter funksjonskallet er: tannregulering { } .

    For eksempel erklærer følgende kode enkel funksjon med navnet kvadrat:

    Funksjon kvadrat(tall) ( returner nummer * tall; )

    Kvadratfunksjonen tar én parameter kalt tall. Den består av en instruksjon, som betyr å returnere parameteren til denne funksjonen (dette er tall) multiplisert med seg selv. Return-setningen spesifiserer verdien som vil bli returnert av funksjonen.

    Returnummer * nummer;

    Primitive parametere (for eksempel et tall) sendes til funksjonen etter verdi; verdien sendes til funksjonen, men hvis funksjonen endrer verdien på parameteren, vil denne endringen ikke reflekteres globalt eller etter at funksjonen er kalt.

    Hvis du sender et objekt som en parameter (ikke et primitivt, for eksempel, eller brukerdefinerte objekter), og funksjonen endrer en egenskap for objektet som sendes til det, vil denne endringen være synlig utenfor funksjonen, som vist i følgende eksempel:

    Funksjon myFunc(theObject) ( theObject.make = "Toyota"; ) var mycar = (merke: "Honda", modell: "Accord", år: 1998); var x, y; x = minbil.merke; // x får verdien "Honda" myFunc(mycar); y = minbil.merke; // y får verdien "Toyota" // (egenskapen ble endret av funksjonen)

    Funksjoner av formen "funksjonsdefinisjonsuttrykk"

    En funksjon av formen "function declaration statement" er en instruksjon i syntaks ( uttalelse), kan en annen funksjon ha formen "funksjonsdefinisjonsuttrykk". En slik funksjon kan være anonym (den har ikke noe navn). For eksempel kan kvadratfunksjonen kalles slik:

    Var kvadrat = funksjon(tall) ( returner tall * tall; ); var x = kvadrat(4); // x får verdien 16

    Imidlertid kan navnet tilordnes til å kalle seg selv innenfor selve funksjonen og for feilsøkeren ( feilsøker) for å identifisere en funksjon i stabelspor ( stabelspor; "spor" - "spor" / "avtrykk").

    Var factorial = funksjon fac(n) ( return n< 2 ? 1: n * fac(n - 1); }; console.log(factorial(3));

    Funksjoner av formen "funksjonsdefinisjonsuttrykk" er nyttige når en funksjon sendes som et argument til en annen funksjon. Følgende eksempel viser en kartfunksjon som skal ta en funksjon som sitt første argument og en matrise som sitt andre.

    Funksjonskart(f, a) ( var resultat = , // Opprett en ny Array i; for (i = 0; i != a.length; i++) resultat[i] = f(a[i]); returner resultat ;)

    I den følgende koden tar funksjonen vår en funksjon, som er et funksjonsdefinisjonsuttrykk, og utfører den på hvert element i den mottatte matrisen som det andre argumentet.

    Funksjonskart(f, a) ( var resultat = ; // Opprett en ny Array var i; // Erklær variabel for (i = 0; i != a.lengde; i++) resultat[i] = f(a[i ]); returner resultat; ) var f = funksjon(x) ( returner x * x * x; ) var tall = ; var kube = kart(f,tall); console.log(kube);

    Funksjonen returnerer: .

    I JavaScript kan en funksjon deklareres med en betingelse. For eksempel vil følgende funksjon bare bli tilordnet til variabelen myFunc hvis num er 0:

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

    I tillegg til funksjonserklæringene som er beskrevet her, kan du også bruke funksjonskonstruktøren til å lage funksjoner fra en streng under kjøretid ( kjøretid), som .

    En metode er en funksjon som er en egenskap til et objekt. Du kan lære mer om objekter og metoder ved å følge lenken: Arbeide med objekter.

    Funksjonsanrop

    Å erklære en funksjon utfører den ikke. En funksjonsdeklarasjon navngir ganske enkelt funksjonen og spesifiserer hva som skal gjøres når funksjonen kalles. Et funksjonskall utfører faktisk de angitte handlingene med de spesifiserte parameterne. For eksempel, hvis du definerer en funksjon kvadrat, kan du kalle den slik:

    Square(5);

    Denne instruksjonen kaller en funksjon med argument 5. Funksjonen kaller instruksjonene og returnerer verdien 25.

    Funksjoner kan være i omfang når de allerede er definert, men funksjoner av formen "funksjonserklæring" kan heises ( heve - heising), akkurat som i dette eksemplet:

    Console.log(square(5)); /* ... */ funksjon kvadrat(n) ( returner n * n; )

    Omfanget til en funksjon er funksjonen den er definert i, eller hele programmet, hvis det er deklarert på et høyere nivå.

    Merk: Dette fungerer bare når funksjonsdeklarasjonen bruker syntaksen ovenfor (dvs. funksjon funcName()). Koden nedenfor vil ikke fungere. Hva dette betyr er at funksjonsheising kun fungerer med funksjonsdeklarasjon og ikke fungerer med funksjonsuttrykk.

    Console.log(square); // kvadrat heves med verdien udefinert. console.log(square(5)); // TypeError: square er ikke en funksjon var square = function(n) ( return n * n; )

    Funksjonsargumenter er ikke begrenset til strenger og tall. Du kan sende hele objekter til en funksjon. Funksjonen show_props() (erklært i Arbeide med objekter) er et eksempel på en funksjon som tar objekter som et argument.

    En funksjon kan kalle seg selv. For eksempel, her er en funksjon for rekursiv beregning av faktorial:

    Funksjon faktoriell(n) ( if ((n === 0) || (n === 1)) returner 1; ellers returnerer (n * faktorial(n - 1)); )

    Du kan deretter beregne faktorialer fra én til fem på denne måten:

    Var a, b, c, d, e; a = faktoriell(1); // a får verdien 1 b = factorial(2); // b får verdien 2 c = factorial(3); // c får verdien 6 d = factorial(4); // d får verdien 24 e = factorial(5); //e får verdien 120

    Det finnes andre måter å kalle en funksjon på. Det er hyppige tilfeller når funksjoner må kalles dynamisk, eller funksjonsargumentnummer må endres, eller en funksjon må kalles i en spesifikk kontekst. Det viser seg at funksjoner i seg selv er objekter, og disse objektene har i sin tur metoder (se objekt ). En av dem er en metode, hvis bruk kan oppnå dette målet.

    Funksjon Omfang

    (funksjonsomfang)

    Variabler som er deklarert i en funksjon kan ikke åpnes noe sted utenfor denne funksjonen, så variabler (som er nødvendig spesifikt for funksjonen) er kun deklarert innenfor funksjonens omfang. I dette tilfellet har funksjonen tilgang til alle variabler og funksjoner som er deklarert innenfor sitt omfang. Med andre ord, en funksjon deklarert i det globale omfanget har tilgang til alle variabler i det globale omfanget. En funksjon som er deklarert inne i en annen funksjon har også tilgang til alle variablene til dens overordnede funksjon og andre variabler som denne overordnede funksjonen har tilgang til.

    // Følgende variabler er deklarert i det globale omfanget var num1 = 20, num2 = 3, navn = "Chamahk"; // Denne funksjonen er deklarert i den globale omfangsfunksjonen multiply() ( return num1 * num2; ) multiply(); // vil returnere 60 // Eksempel på en nestet funksjon funksjon getScore() ( var num1 = 2, num2 = 3; funksjon add() ( return name + "scored" + (num1 + num2); ) return add(); ) getScore( ); // vil returnere "Chamahk scoret 5"

    Omfang og funksjonsstabel

    (funksjonsstabel)

    Rekursjon

    En funksjon kan kalle seg selv. Tre måter å kalle dette:

  • etter funksjonsnavn
  • av en variabel som refererer til en funksjon
  • Tenk for eksempel på følgende funksjon:

    Var foo = funksjonslinje() ( // utsagn går hit );

    Inne i funksjonen ( funksjon kroppen) alle følgende samtaler er likeverdige:

  • bar()
  • arguments.callee()
  • foo()
  • En funksjon som kaller seg selv kalles rekursiv funksjon (rekursiv funksjon). Det viser seg at rekursjon ligner på en løkke ( Løkke). Begge kaller en kode flere ganger, og begge krever en betingelse (for å unngå endeløs løkke, eller rettere sagt uendelig rekursjon). For eksempel følgende loop:

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

    kunne endres til rekursiv funksjon og kaller denne funksjonen:

    Funksjonsløkke(x) ( if (x >= 10) // "x >= 10" er betingelsen for slutten av utførelse (samme som "!(x)< 10)") return; // делать что-то loop(x + 1); // рекурсионный вызов } loop(0);

    Noen algoritmer kan imidlertid ikke være enkle iterative løkker. For eksempel, å få alle elementene i en trestruktur (for eksempel ) er enklest implementert ved å bruke rekursjon:

    Funksjon walkTree(node) ( if (node ​​== null) // return; // gjør noe med elementene for (var i = 0; i< node.childNodes.length; i++) { walkTree(node.childNodes[i]); } }

    Sammenlignet med loop-funksjonen, forårsaker hvert rekursivt anrop i seg selv mange rekursive anrop.

    Det er også mulig å transformere noen rekursive algoritmer til ikke-rekursive, men ofte er logikken deres veldig kompleks og vil kreve bruk av en stack ( stable). Faktisk bruker rekursjon stach: function stack.

    Oppførselen til stabelen" kan sees i følgende eksempel:

    Funksjon 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

    Nestede funksjoner og lukkinger

    Du kan legge en funksjon inne i en annen. Nestet funksjon ( nestet funksjon;indre) privat ( privat) og den plasseres i en annen funksjon ( ytre). Slik er det dannet kortslutning (stenging). En lukking er et uttrykk (vanligvis en funksjon) som kan ha frie variabler, sammen med et miljø som binder disse variablene (som "lukker" ( "Lukk") uttrykk).

    Siden en nestet funksjon er en lukking, betyr dette at den nestede funksjonen kan "arve" ( arve) argumenter og variabler for funksjonen den er nestet i. Med andre ord inneholder den nestede funksjonen omfanget til den ytre ( "ytre") funksjoner.

    Oppsummer:

    • En nestet funksjon danner en lukking: den kan bruke argumentene og variablene til den ytre funksjonen, mens den ytre funksjonen ikke kan bruke argumentene og variablene til den nestede funksjonen.

    Følgende eksempel viser en nestet funksjon:

    Funksjon addSquares(a, b) ( funksjon square(x) ( return x * x; ) return square(a) + square(b); ) a = addSquares(2, 3); // returnerer 13 b = addSquares(3, 4); // returnerer 25 c = addSquares(4, 5); // returnerer 41

    Fordi den nestede funksjonen danner lukkingen, kan du kalle den ytre funksjonen og gi argumenter for begge funksjonene (ytre og indre).

    Funksjon utenfor(x) ( funksjon inne(y) ( returner x + y; ) returnerer inne; ) fn_inside = outside(3); // Tenk på det: gi meg en funksjon // som passerer 3 resultat = fn_inside(5); // returnerer 8 resultat1 = utenfor(3)(5); // returnerer 8

    Lagre variabler

    Merk at verdien av x ble bevart da innsiden ble returnert. Lukking må bevare argumenter og variabler i hele omfanget. Siden hver samtale gir potensielt forskjellige argumenter, opprettes en ny stenging for hver samtale til utsiden. Minnet kan bare tømmes når innsiden allerede har kommet tilbake og ikke lenger er tilgjengelig.

    Dette er ikke forskjellig fra å lagre referanser i andre objekter, men er ofte mindre åpenbart fordi referansene ikke er direkte satt og ikke kan ses der.

    Multipliserte funksjoner

    Funksjoner kan legges inn flere ganger, dvs. funksjon (A) lagrer funksjon (B), som lagrer funksjon (C). Begge funksjonene B og C danner lukkinger, så B har tilgang til A sine variabler og argumenter, og C har samme tilgang til B. I tillegg, siden C har tilgang til B som har samme tilgang til A, har C også slik tilgang samme tilgang til A. Dermed kan cloures lagre flere scopes; de lagrer rekursivt omfanget av funksjonene som inneholder det. Det kalles lenking (kjede - kjede; Hvorfor det kalles "kjetting" vil bli forklart senere)

    Tenk på følgende eksempel:

    Funksjon A(x) ( funksjon B(y) (funksjon C(z) ( console.log(x + y + z); ) C(3); ) B(2); ) A(1); // konsollen vil vise 6 (1 + 2 + 3)

    I dette eksemplet har C tilgang til y av funksjon B og x til funksjon A. Dette skjer fordi:

  • Funksjon B genererer en lukking som inkluderer A , dvs. B har tilgang til argumenter og funksjonsvariabler EN.
  • Funksjon C oppretter en lukking som inkluderer B .
  • Siden lukkingen av funksjon B inkluderer A, så inkluderer lukkingen av C også A, C har tilgang til argumentene og variablene til begge funksjonene B Og EN. Med andre ord, C binder seg kjede (kjede) omfanget av funksjonene B og A i den rekkefølgen.
  • Omvendt er dette imidlertid ikke sant. A har ikke tilgang til Cs variabler og argumenter fordi A ikke har slik tilgang til B. På denne måten forblir C privat kun for B.

    Navnekonflikter

    Når to argumenter eller variabler i lukkingens omfang har samme navn, skjer navnekonflikt (navnekonflikt). Mer nestet ( mer indre) omfang har prioritet, så det mest nestede omfanget har høyest prioritet, og omvendt. Dette er en kjede av omfang ( omfangskjede). Det aller første leddet er det dypeste omfanget, og omvendt. Vurder følgende:

    Funksjon utenfor() ( var x = 5; funksjon inne(x) ( returner x * 2; ) returnerer inne; ) utenfor())(10); // returnerer 20 i stedet for 10

    Det oppsto en navnekonflikt i retur x * 2-setningen mellom parameteren x for den indre funksjonen og variabelen x til den ytre funksjonen. Scope-kjeden her vil være slik: ( inne ==> utenfor ==> globalt objekt ( globalt objekt)). Derfor har x-en til den indre funksjonen forrang over den ytre funksjonen, og vi får tilbake 20 (= 10 * 2) i stedet for 10 (= 5 * 2).

    Nedleggelser

    (Stenginger)

    Lukking er en av hovedfunksjonene til JavaScript. JavaScript tillater funksjonsnesting og gir nestede funksjoner full tilgang til alle variabler og funksjoner som er deklarert inne i den ytre funksjonen (og andre variabler og funksjoner som den ytre funksjonen har tilgang til).

    Den ytre funksjonen har imidlertid ikke tilgang til variablene og funksjonene som er deklarert i den indre funksjonen. Dette gir en slags innkapsling for variablene inne i den nestede funksjonen.

    Siden en nestet funksjon har tilgang til omfanget av den ytre funksjonen, vil variabler og funksjoner som er deklarert i den ytre funksjonen fortsette å eksistere etter at den er utført for den nestede funksjonen, hvis tilgangen til dem og den opprettholdes (som betyr at variabler deklarert i de ytre funksjonsfunksjonene lagres bare hvis en indre funksjon har tilgang til dem).

    En lukking opprettes når en nestet funksjon på en eller annen måte har blitt tilgjengelig i et eller annet omfang utenfor den ytre funksjonen.

    Var pet = funksjon(navn) ( // Den ytre funksjonen erklærte variabelen "navn" var getName = function() ( return name; // Den nestede funksjonen har tilgang til "navnet" til den ytre funksjonen ) return getName; / / Returner den nestede funksjonen, og bevar dermed tilgangen // til den for et annet omfang) myPet = pet("Vivie"); kjæledyret mitt(); // "Vivie" returneres, // fordi selv etter å ha utført den ytre funksjonen // er navnet bevart for den nestede funksjonen

    Mer komplekst eksempel presentert nedenfor. Et objekt med metoder for å manipulere den nestede funksjonen med den ytre funksjonen kan returneres ( komme tilbake).

    Var createPet = function(name) ( var sex; return ( setName: function(newName) ( name = newName; ), getName: function() ( return name; ), getSex: function() ( return sex; ), setSex: function(newSex) ( if(typeof newSex === "string" && (newSex.toLowerCase() === "male" || newSex.toLowerCase() === "female")) ( sex = newSex; ) ) ) ) var pet = createPet("Vivie"); pet.getName(); // Vivie pet.setName("Oliver"); pet.setSex("mann"); pet.getSex(); // mannlig pet.getName(); // Oliver

    I koden ovenfor er navnevariabelen til den ytre funksjonen tilgjengelig for den nestede funksjonen, og det er ingen annen måte å få tilgang til de nestede variablene enn gjennom den nestede funksjonen. De nestede variablene til en nestet funksjon er sikre lagringsmuligheter for eksterne argumenter og variabler. De inneholder "vedvarende" og "innkapslede" data for nestede funksjoner å manipulere. Funksjoner trenger ikke engang å være tilordnet en variabel eller ha et navn.

    Var getCode = (function() ( var apiCode = "0]Eal(eh&2"; // En kode vi ikke vil at utenforstående skal kunne endre... return function() ( return apiCode; ); )()) ; getCode(); // Returnerer apiCode

    Det er imidlertid en del fallgruver å være oppmerksom på ved bruk av lukkinger. Hvis privat funksjon definerer en variabel med samme navn som variabelnavnet i det ytre omfanget, er det ingen måte å referere til variabelen i det ytre omfanget igjen.

    Var createPet = function(name) ( // Den ytre funksjonen definerer en variabel kalt "navn". return ( setName: function(name) ( // Den vedlagte funksjonen definerer også en variabel kalt "navn". navn = navn; // Hvordan får vi tilgang til "navnet" definert av den ytre funksjonen? ) ) )

    Bruke arguments-objektet

    Funksjonens arguments-objekt er en pseudo-array. Inne i en funksjon kan du referere til argumenter som dette:

    Argumenter[i]

    der i er ordinærtallet til argumentet, fra 0. Det første argumentet som sendes til funksjonen adresseres som argumenter . Og få nummeret på alle argumenter - arguments.length .

    Ved å bruke arguments-objektet kan du kalle en funksjon ved å sende flere argumenter til den enn den formelt ble erklært å akseptere. Dette er veldig nyttig hvis du ikke vet nøyaktig hvor mange argumenter funksjonen din skal ta. Du kan bruke arguments.length for å bestemme antall argumenter som sendes til en funksjon, og deretter få tilgang til hvert argument ved å bruke arguments-objektet.

    Tenk for eksempel på en funksjon som setter sammen flere strenger. Det eneste formelle argumentet til funksjonen vil være en streng som spesifiserer tegnene som skiller elementene som skal settes sammen. Funksjonen er definert som følger:

    Funksjon myConcat(separator) ( var resultat = ""; var i; // iterer gjennom argumenter for (i = 1; i< arguments.length; i++) { result += arguments[i] + separator; } return result; }

    Du kan sende et hvilket som helst antall argumenter til denne funksjonen, og den vil sette sammen hvert argument i én streng.

    // returnerer "rød, oransje, blå, " myConcat(", ", "rød", "oransje", "blå"); // returnerer "elefant; sjiraff; løve; gepard; " myConcat("; ", "elefant", "siraff", "løve", "gepard"); // returnerer "salvie. basilikum. oregano. pepper. persille." myConcat(". ", "salvie", "basilikum", "oregano", "pepper", "persille");

    Fordi argumenter er en pseudo-array, noen array-metoder gjelder for den, for eksempel for .. in

    Funksjon func() ( for (verdi i argumenter)( console.log(verdi); ) ) func(1, 2, 3); // 1 // 2 // 3

    Merk: argumenter er en pseudo-matrise, men ikke en matrise. Dette er en pseudo-array som har nummererte indekser og lengde eiendom. Den har imidlertid ikke alle array-metoder.

    Hvileparametere

    Innføringen av pilfunksjoner ble påvirket av to faktorer: kortere funksjoner og dette leksikonet.

    Kortere funksjoner

    Noen funksjonelle mønstre oppfordrer til bruk av kortere funksjoner. Sammenligne:

    Var a = [ "hydrogen", "helium", "litium", "beryllium" ]; var a2 = a.map(funksjon(er) (retur s.length; )); console.log(a2); // logger var a3 = a.map(s => s.length); konsoll.log(a3); // tømmerstokker

    Ordforråd dette

    Opp til pilfunksjoner hver ny funksjon definert denne verdien (et nytt objekt i tilfelle av en konstruktør, udefinert i streng modus, et kontekstobjekt hvis funksjonen kalles som en metode for et objekt, etc.). Dette viste seg å være irriterende sett fra den objektorienterte programmeringsstilen.

    Funksjon Person() ( // Person()-konstruktøren definerer `this` som seg selv. this.age = 0; setInterval(function growUp() ( // Uten streng modus definerer growUp()-funksjonen `this` // som et globalt objekt , som er forskjellig fra `this` // definert av Person()-konstruktøren. this.age++; ), 1000); ) var p = new Person();

    I ECMAScript 3/5 ble dette problemet løst ved å tilordne verdien av dette til en variabel som kunne sløyfes.

    Funksjon Person() ( var self = this; // Noen velger `det` i stedet for `selv`. // Velg en og vær konsekvent. self.age = 0; setInterval(function growUp() ( // Tilbakekallingen til "selv"-variabelen som refererer til // verdien er det forventede objektet. self.age++; ), 1000); )

    Se også funksjon i JavaScript-referansen for tilleggsinformasjon etter funksjon som et objekt.