Js pilfunktioner. Om JavaScript-nyckelordet "detta": funktioner för användning med förklaringar. Regler för användning av pilfunktioner

De har blivit väldigt moderiktiga, vi ser dem i alla nya artiklar. Och om du inte är van vid dem kommer du att ha svårt att förstå modern (ES6) kod som innehåller pilfunktioner.

Den här artikeln är inte avsedd att berätta när eller hur du ska använda dem. Jag ska bara försöka förklara den nya syntaxen för dem som ser den för första gången. Om du använder det eller inte är inte viktigt, men förr eller senare kommer du fortfarande att stöta på det någonstans. Så det är bättre att förstå mekaniken i denna nya syntax.

Här är ett litet exempel:

Const addOne = funktion(n) (retur n + 1; )

Ovanstående kod kan skrivas så här:

Const addOne = (n) => (retur n + 1; )

Eller, i det här fallet, ännu kortare:

Const addOne = (n) => n + 1;

Det andra exemplet använder ( ... ) hängslen, men eftersom det bara är en kodrad, kan hängslen utelämnas och returen antyds, som ses i det tredje exemplet.

En parameter

När en pilfunktion har en parameter kan parentesen utelämnas:

// Var: someCallBack((resultat) => ( ... )) // Nu: someCallBack(resultat => ( ... ))

Men om det inte finns några parametrar måste du använda öppnings- och stängningsparenteser:

SomeCallBack(() => ( ... ))

Återuppringningsfunktioner

Funktionspilar är särskilt användbara för återuppringningar. De som är bekanta med JavaScript är bekanta med dess lexikaliska omfattning, vilket är ganska snyggt, men kan göra såna här tricks ( detta):

Var_detta = detta; someCallBack(function() ( _this.accessOuterScope(); ))

Det finns flera varianter av detta "_detta" (som "jaget" eller "det"), men idén är densamma. I callback-funktioner behöver vi tillgång till den yttre scope-versionen, men tanken är densamma. I callback-funktioner behöver vi tillgång till det yttre scopets version av denna , som nu skiljer sig från tidigare eftersom vi pratar om en callback-funktion.

Genom att använda pilfunktioner, får vi "block scope" och "this", vilket är samma "this" i båda fallen. Det betyder att koden ovan kan skrivas om utan _this = this:

SomeCallBack(() => ( this.accessOuterScope(); ))

"Omslag"

Låt oss föreställa oss en situation som i React, där händelsen påKlicka bör anropa doSomething(), (), men bör också skicka argument till doSomething() (t.ex. ID). Det här exemplet fungerar faktiskt inte:

Någon användare)))

Koden kommer att köras, men tekniskt sett kommer den att anropa doSomething() omedelbart när sidan laddas. För att lösa detta problem hänvisar vissa utvecklare till en omslagsfunktion:

Const User = React.createClass(function() (render: function() (retur Vissa användare), onClick: function() ( doSomething(this.props.userId); ) ))

Avsaknaden av en parentes i this.onClick betyder att det helt enkelt är en funktionsreferens snarare än ett funktionsanrop.

OnClick()-funktionen är nu något av en wrapper för doSomething() . Med pilfunktioner kan du göra "omslag" av denna typ:

Const User = React.createClass(function() (render: function() (retur doSomething(this.props.userId))>Någon användare ) ))

Som ett alternativ kan vi också använda .bind() , som inte kräver några omslag (pilfunktioner eller något annat):

Const User = React.createClass(function() ( render: function() ( return Some user ) ))

Webbläsarstöd för pilfunktioner

Om du behöver webbläsarstöd annat än senaste versionerna Krom Och Firefox, använda sig av Babel transpiler för att konvertera ES6-koden du skrev till ES5.

ES6 har ett nytt sätt att skapa funktioner - Använda pilen => operatorn. Sådana funktioner kallas pilfunktioner. De erbjuder en mer kompakt syntax. De har inget namn och de jobbar annorlunda med det här .

Det första vi kommer att göra är att köra ett Babel-skript som kommer att övervaka filerna och skapa nya versioner när de ändras.

Öppna projektmappen i kommandorad(KS). Ange kommandot:

Och tryck på Enter

I src-mappen kommer vi att skapa en fil arr.js och omedelbart ange den i filen index.html

</script>

De senaste versionerna av webbläsare stöder pilfunktioner utan transpilering och min webbläsare är en av dem.

Låt oss skriva en funktion som adderar två tal och returnerar deras summa. Låt oss kalla funktionen add .

Funktion add (x, y) ( return x + y; ) console.log (add (3, 6));

I konsolen kommer vi att se resultatet - 9

Låt oss nu konvertera denna funktion till en pilfunktion.

Låt oss ta bort ordet funktion , ta bort funktionsnamnet och ta bort klammerparenteserna och ordet - retur . Efter parametrarna sätter vi en pil.

Låt addera = (x, y) => x + y; console.log(add(4, 6));

Om du tittar på typen av add-variabel med hjälp av typen av operator:

Console.log(typeof(add));

Detta är vad vi kommer att se i funktionskonsolen

Det betyder att pilfunktioner är vanliga funktioner. Och du kan verifiera detta genom att titta på den transpilerade koden.

"använd strikt"; var _typeof = typ av Symbol === "funktion" && typ av Symbol.iterator === "symbol" ? function (obj) ( return typeof obj; ) : function (obj) ( return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj ; ); var add = funktion add(x, y) (retur x + y; ); console.log(add(4, 6)); console.log(typeof add === "odefinierad" ? "odefinierad" : _typeof(add));

Vi kan se att Babel har förvandlat vår kod till ett enkelt funktionsuttryck.

Låt oss skriva en enkel funktion som ska kvadrera ett givet tal.

Låt addera = (x, y) => x + y; console.log(add(4, 6)); console.log(typeof(add)); låt kvadrat = function(a) ( returnera en * a; ) console.log(square (4));

Låt oss titta i konsolen:

Pilfunktionen kommer att se ut så här:

Låt kvadrat = x => x * x;

Om en pilfunktion bara tar en parameter, behöver du inte sätta den inom parentes!

Låt oss skriva en funktion som inte tar några parametrar alls.

Funktion givNumer () ( return 33; ) console.log(givNumer ());

Denna funktion skriver helt enkelt ut siffran 33 till konsolen. Pil:

Låt givNumer = () => 33; console.log(givNumer());

Låt oss skapa en funktion som inte returnerar något. Det kommer helt enkelt att visa ett meddelande i webbläsarkonsolen.

Låt log = function () ( console.log("Hello World!"); ); logga();

Växla:

Låt log = () => console.log("Hej världen!!!"); logga();

Låt oss skapa en funktion vars kropp kommer att bestå av två linjer.

Funktionen kommer att ha två parametrar. Låt oss skapa en variabel i funktionens kropp. Efter det återkommer vi resultatet.

Låt mult = funktion (a, b) ( låt resultat = a * b; returnera resultat; ) console.log(mult (4, 5));

Om det finns flera rader i en pilfunktion, så krävs lockiga hängslen - ()! Och se till att definiera vad den här funktionen returnerar med nyckelordet return

Växla:

Låt mult = (a, b) => (låt resultat = a * b; returnera resultat; ) console.log(mult (4, 5));

Låt oss nu skapa en funktion som returnerar ett objekt bokstavligt:

Låt literal = funktion () ( return ( namn: "John"); ) console.log (literal ());

I konsolen kommer vi att se:

Låt oss nu försöka skapa en pilfunktion som returnerar ett objekt bokstavligt.

Man bör komma ihåg att om en pilfunktion returnerar ett objekt bokstavligt, så behövs parenteser - ()

Pilfunktion som returnerar ett objekt bokstavligt:

Låt bokstavlig = () => ((namn: "John")); console.log(literal());

Låt oss nu försöka använda pilfunktionen som ett IIFE - Immediately-anroped function expression

Kort sagt är detta en funktion som exekveras direkt efter deklarationen

Det ser ut så här:

(function () ( console.log("IIFE"); ))();

Pil-IIFE-funktionen kommer att se ut så här:

(() => console.log("IIFE"))();

En viktig egenskap hos pilfunktioner är att pilen måste komma direkt efter parametrarna!

Du kan inte bara ta den och flytta den ner till en rad nedanför. Det kommer att ge ett fel!

Praktisk tillämpning av pilfunktioner. Pilfunktioner är mycket bekväma att använda med arrayer.

Låt oss skapa en array med några nummer och kalla den nummer . Jag tror att du vet att arrayer har användbara metoder som låter dig iterera genom arrayen, filtrera den osv.

Låt oss beräkna summan av alla arrayvariabler. För att göra detta kommer jag att deklarera en annan variabel - låt summa = 0;

Låt oss använda metoden forEach() som varje array har, vi itererar över elementen och lägger till summan.

Låt siffror = ; låt summa = 0; numbers.forEach(function(num) ( summa += num; )); console.log(summa);

I konsolen kommer vi att se 55. Låt oss förvandla den här funktionen till en pilfunktion: numbers.forEach(num => summa += num); console.log(summa);

Alltså, det som tidigare tog oss tre rader tar nu en.

Vi kan också kvadrera varje element i arrayen.

Låt kvadrat = siffror.map(n => n * n); console.log(kvadrat);

Pilfunktioner och detta. För att göra detta kommer jag att skapa ett objekt literal som jag sparar i personvariabeln.

Personobjektet kommer att ha en namnegenskap med värdet 'Bob' och en greet-egenskap med värdet 'Greet'. Vi kommer att skriva ut hälsningen till konsolen och även titta på syftet med detta.

Låt person = ( namn: "Bob", hälsa: function () ( console.log("Hej! Jag heter " + detta.namn); console.log(detta); ) ); person.greet();

I webbläsarkonsolen kommer vi att se hälsningen och själva personens objekt.

Nu ska vi ersätta funktionen med en pil och se vad som händer med detta .

Låt person = ( namn: "Bob", hälsa: () => ( console.log("Hej! Jag heter " + detta.namn); console.log(detta); ) ); person.greet();

Nu fick vi inte värdet på namnet och värdet på detta är fönster !

Men varför? Poängen är att värdet av detta är hämtat från det sammanhang där funktionen deklareras. ! Oavsett var denna funktion kommer att utföras. Detta kan ses på bilden:

Vi har ett program.

Än så länge finns det inget i den förutom fönsterobjektet. Lade till ett personobjekt. Observera att vi använder en pilfunktion för metoden. Som vi sa kommer värdet av detta att tas från sammanhanget. Kontext är miljön. I det här fallet kommer miljön för personobjektet, alla dess egenskaper och metoder att vara fönsterobjekt. Och om värdet av detta tas från sammanhanget, kommer detta att hänvisa till fönsterobjektet.

Om vi ​​tittar på en vanlig funktion så vet vi att det här syftar på själva personobjektet. Du kanske frågar varför värdet av detta i pilfunktioner tas från sammanhanget? Och svaret är väldigt enkelt - de gjorde det på det sättet! :-) Poängen är att pilfunktioner skapades för att lösa problem i en annan situation. Låt oss titta på ett exempel. För att se problemet återgår vi till vår pilfunktion.

Låt person = ( namn: "Bob", hälsa: function () ( console.log("Hej! Jag heter " + detta.namn); console.log(detta); ) );

Låt oss föreställa oss att vår Bob är ganska upptagen och behöver ett par sekunder för att slutföra sitt arbete. Vänta 2 sekunder. vi simulerar med funktionen setTimeout(); .Denna funktion tar en funktion som den första parametern och antalet millisekunder att vänta som den andra parametern.

Låt person = ( namn: "Bob", hälsa: function () ( setTimeout(function () ( console.log("Hej! Jag heter " + detta.namn); console.log(this); ), 2000) ;) ); person.greet();

Om du har erfarenhet av JavaScript så tror jag att du förstår vad problemet är. Hur som helst, låt oss titta på vad som kommer att hända i webbläsaren. Exakt två sekunder senare kommer vi att se den här bilden i webbläsaren.

Men varför? Om du tittar på vår kod är det logiskt att anta. att detta syftar på personobjektet eftersom vi använder en vanlig funktion. Saken är att setTimeout() tillhör fönsterobjektet. Om du skriver det så här: window.setTimeout() , vad tror du då syftar på? Och i konsolen kommer vi att få samma resultat! Det finns flera sätt att lösa detta problem i ES5. Vi ska titta på den vanligaste: Innan setTimeout() ska jag deklarera en annan variabel som och tilldela denna som värdet. Och nu, i funktionens kropp, istället för detta, kommer vi att indikera det.

Låt person = ( namn: "Bob", hälsa: funktion () ( låt det = detta; setTimeout(funktion () ( console.log("Hej! Jag heter " + that.name); console.log(that) ; ), 2000); ) ); person.greet();

Nu, tack vare stängningen, kommer funktionen vi skickar till setTimeout() att ha tillgång till variabeln that, vars värde kommer att vara detta , det vill säga i det här fallet personobjektet.

För tydlighetens skull kan du titta på vad vårt det och det här syftar på.

Låt person = ( namn: "Bob", hälsa: funktion () ( låt det = detta; setTimeout(funktion () ( console.log("Hej! Jag heter " + that.name); console.log("It is my That = " + that); console.log("It is my This = " + this); ), 2000); ) ); person.greet();

Vi kommer att se bekräftelse i konsolen:

Vi ser att detta kommer att vara fönsterobjektet - This = , och det kommer att vara vårt personobjekt - That = .

I ES6 kan vi helt enkelt använda en pilfunktion för att lösa detta problem.

Låt person = ( namn: "Bob", hälsa: function () ( setTimeout(() => ( console.log("Hej! Jag heter " + detta.namn); console.log("Det är min Detta = " + detta); ), 2000); ) ); person.greet();

Som ett resultat kommer vi att se i konsolen:

I grafiskt exempel för en pilfunktion kommer kontexten att vara ett personobjekt, inte ett fönsterobjekt. det är därför detta kommer att hänvisa till person.

Förutom kompakt syntax introducerades pilfunktioner för att lösa problem som dessa.

Som referens kan du se hur Babel löste detta

Var person = ( namn: "Bob", greet: function greet() ( var _this = this; setTimeout(function () ( console.log("Hej! Jag heter " + _this.name); console.log(" Det är min This = " + _this); ), 2000); ) ); person.greet(); Babel använde samma metod som vi använde i ES5. Den enda skillnaden är att vi kallade variabeln det, och Babel kallade den - _this. Tack vare stängningen kommer funktionen vi skickar till setTimeout att ha tillgång till variabeln _this och, som ett resultat, till personobjektet.

Jag tror att den svåraste delen av den här delen är att förstå hur stängningar fungerar.

Några fler funktioner i pilfunktioner:
Du kan se mer information om ES6 och pilfunktioner i mitt inlägg

Hej alla! I den här artikeln ska vi titta på vilka pilfunktioner som finns i ES6 och hur man använder dem.

Pilfunktioner är funktioner som skrivs med piloperatorn (=>).

Låt oss genast titta på ett exempel:

Låt addera = (x, y) => x + y;
console.log(add(5, 2));

Som ett resultat av att utföra denna funktion kommer vi att se siffran 7 i konsolen.

Först skickar vi argumenten inom parentes, sedan sätter vi piltecknet och sedan skriver vi koden för själva funktionen. I vårt fall tar det helt enkelt två siffror och lägger till dem. I teorin är detta detsamma som funktionsuttryck i ES5. Om du använder Babel eller liknande kompilatorer kommer de med största sannolikhet att skriva något så här:

Var add = funktion add(x, y) (
returnera x + y;
};

Om din funktion bara tar en parameter är parentesen valfri.

Låt kvadrat = x => x*x;

Denna funktion tar bara ett argument och kvadrerar det givna talet.

Funktion utan parametrar:

Låt func = () => 77;

Om din funktion innehåller flera rader, måste du för det första använda hängslen, och för det andra, se till att skriva vad funktionen returnerar, d.v.s. använd nyckelordet retur.

Låt multiplicera = (x, y) => (
låt resultatet = x*y;
returnera resultat;
};

Om du behöver returnera ett objekt bokstavligt, måste du slå in det inom parentes:

Låt getObject = () => (( varumärke: "BMW" ));

Den självanropande funktionen ser ut så här:

Ett pilfunktionsuttryck är ett syntaktiskt kompakt alternativ till ett reguljärt funktionsuttryck, men utan sina egna bindningar till nyckelorden this , arguments , super eller new.target. Pilfunktionsuttryck är illa lämpade som metoder, och de kan inte användas som konstruktörer.

Syntax Grundläggande syntax (param1, param2, …, paramN) => ( satser ) (param1, param2, …, paramN) => uttryck // motsvarar: => (retur uttryck; ) // Parenteser är valfria när det finns endast ett parameternamn: (singleParam) => ( satser ) singleParam => ( satser ) // Parameterlistan för en funktion utan parametrar ska skrivas med ett par parenteser. () => ( satser ) Avancerad syntax // Placera en funktions parentes för att returnera ett bokstavligt objektuttryck: params => ((foo: bar)) // Restparametrar och standardparametrar stöds (param1, param2, ...rest) => (satser ) (param1 = defaultValue1, param2, …, paramN = defaultValueN) => ( satser ) // Destrukturering inom parameterlistan stöds också var f = ( = , (x: c) = (x: a + b)) => a + b + c; f(); // 6 Beskrivning

Två faktorer påverkade införandet av pilfunktioner: behovet av kortare funktioner och beteendet hos detta nyckelord.

Shorter functions var elements = [ "Väte", "Helium", "Lithium", "Beryllium" ]; // Denna sats returnerar arrayen: elements.map (function(element) (retur element.length; )); // Den vanliga funktionen ovan kan skrivas som pilfunktionen under elements.map((element) => (retur element.length; )); // // När det bara finns en parameter kan vi ta bort de omgivande parenteserna elements.map (element => ( return element.length; )); // // När den enda satsen i en pilfunktion är `return`, kan vi ta bort `return` och ta bort // de omgivande parenteserna elements.map(element => element.length); // // I det här fallet, eftersom vi bara behöver egenskapen length, kan vi använda destructuring parameter: // Lägg märke till att `length` motsvarar egenskapen vi vill få medan // uppenbarligen icke-speciell `lengthFooBArX` är bara namnet på en variabel som kan ändras // till vilket giltigt variabelnamn du vill ha elements.map ((( length:lengthFooBArX )) => lengthFooBArX); // // Denna destkan också skrivas enligt nedan. Observera dock att i // det här exemplet tilldelar vi inte 'längd'-värdet till den påhittade egenskapen. Istället används det bokstavliga namnet // på variabeln `length` som egenskapen vi vill hämta från objektet. elements.map (((längd)) => längd); // Inget skilja detta

Innan pilfunktionerna definierade varje ny funktion sitt eget detta värde baserat på hur funktionen anropades:

  • Ett nytt objekt i fallet med en konstruktör.
  • odefinierad i strikt läge funktionsanrop.
  • Basobjektet om funktionen anropades som en "objektmetod".

Detta har visat sig vara mindre än idealiskt med en objektorienterad programmeringsstil.

Funktion Person() ( // Person()-konstruktorn definierar `this` som en instans av sig själv. this.age = 0; setInterval(funktion growUp() ( // I icke-strikt läge definierar growUp()-funktionen ` this` // som det globala objektet (eftersom det är där growUp() exekveras.), // som skiljer sig från `this` // definierad av Person()-konstruktorn. this.age++; ), 1000) ; ) var p = ny person();

I ECMAScript 3/5 kunde det här problemet åtgärdas genom att tilldela värdet i detta till en variabel som kunde stängas över.

Funktion Person() ( var that = this; that.age = 0; setInterval(function growUp() ( // Återuppringningen refererar till variabeln `that` av vilken // värdet är det förväntade objektet. that.age++; ) , 1000); ) "använd strikt"; var obj = (a: 10); Object.defineProperty(obj, "b", ( get: () => ( console.log(this.a, typeof this.a, this); // undefined "odefinierat" fönster (...) (eller det globala object) returnera this.a + 10; // representerar det globala objektet "Window", därför returnerar "this.a" "undefined" ) ));

Användning av den nya operatören

Pilfunktioner kan inte användas som konstruktörer och ger ett felmeddelande när de används med new .

Var Foo = () => (); var foo = new Foo(); // TypeError: Foo är inte en konstruktör

Användning av prototypegenskap

Pilfunktioner har ingen prototypegenskap.

Var Foo = () => (); console.log(Foo.prototype); // odefinierat

Användning av nyckelordet avkastning

Nyckelordet yield får inte användas i en pilfunktions kropp (förutom när det är tillåtet i funktioner som är ytterligare kapslade i den). Som en konsekvens kan pilfunktioner inte användas som generatorer.

Funktionskropp

Pilfunktioner kan ha antingen en "koncis kropp" eller den vanliga "blockkroppen".

I en kortfattad kropp anges endast ett uttryck, som blir det implicita returvärdet. I en blockkropp måste du använda en explicit retursats.

Var func = x => x * x; // kortfattad kroppssyntax, underförstådd "return" var func = (x, y) => (retur x + y; ); // med blockkropp, explicit "retur" behövs

Returnerar objekts bokstavliga ord

Tänk på att returnering av objektliteraler med de kortfattade kroppssyntaxparametrarna => (objekt:literal) inte kommer att fungera som förväntat.

Var func = () => ( foo: 1 ); // Att anropa func() returnerar odefinierat! var func = () => ( foo: function() () ); // SyntaxError: funktionssats kräver ett namn

Detta beror på att koden inom klammerparenteser (()) tolkas som en sekvens av påståenden (dvs. foo behandlas som en etikett, inte en nyckel i ett objekts bokstavligt tal).

Du måste slå in objektet bokstavligt inom parentes:

Var func = () => (( foo: 1 ));

Radbrytningar

En pilfunktion kan inte innehålla en radbrytning mellan dess parametrar och dess pil.

Var func = (a, b, c) => 1; // SyntaxError: förväntat uttryck, fick "=>"

Detta kan dock ändras genom att sätta radbrytningen efter pilen eller använda parenteser/parenteser som visas nedan för att säkerställa att koden förblir vacker och fluffig. Du kan också lägga radbrytningar mellan argument.

Var func = (a, b, c) => 1; var func = (a, b, c) => (1); var func = (a, b, c) => (retur 1); var func = (a, b, c) => 1; // inget SyntaxError kastat

Parsningsordning

Även om pilen i en pilfunktion inte är en operator, har pilfunktioner speciella tolkningsregler som interagerar annorlunda med operatorprioritet jämfört med vanliga funktioner.

Låt återuppringning; återuppringning = återuppringning || fungera(); // ok återuppringning = återuppringning || () => (); // SyntaxError: ogiltiga pilfunktionsargument callback = callback || (() => ()); // okej

Fler exempel // En tom pilfunktion returnerar undefined let empty = () => (); (() => "foobar")(); // Returnerar "foobar" // (detta är ett omedelbart anropat funktionsuttryck) var simple = a => a > 15 ? 15:a; enkel(16); // 15 enkel(10); // 10 låt max = (a, b) => a > b ? a:b; // Enkel arrayfiltrering, mappning, ... var arr = ; var summa = arr.reduce((a, b) => a + b); // 66 var jämn = arr.filter(v => v % 2 == 0); // var double = arr.map(v => v * 2); // // Mer kortfattade löfteskedjor lovar.then(a => ( // ... )).then(b => ( // ... )); // Parameterlösa pilfunktioner som är visuellt lättare att analysera setTimeout(() => ( console.log("Jag händer förr"); setTimeout(() => ( // deeper code console.log("Jag händer senare") ; ), elva); Specifikationer Specifikation Status Kommentar
ECMAScript 2015 (6:e upplagan, ECMA-262)
Standard Initial definition.
ECMAScript senaste utkast (ECMA-262)
Definitionen av "Arrow Function Definitions" i den specifikationen.
Förslag
Webbläsarkompatibilitet

Kompatibilitetstabellen på den här sidan genereras från strukturerad data. Om du vill bidra till datan, kolla in https://github.com/mdn/browser-compat-data och skicka oss en pull-förfrågan.

Uppdatera kompatibilitetsdata på GitHub

Desktop Mobile Server Chrome Edge Firefox Internet Explorer Opera Safari Android webbvy Chrome för Android Firefox för Android Opera för Android Safari på iOS Samsung Internet Node.jsPilfunktioner Efterföljande kommatecken i parametrar
Chrome Fullt stöd 45Edge Fullt stöd JaFirefox Fullt stöd 22

Anteckningar

Fullt stöd 22

Anteckningar

Anteckningar Före Firefox 39 var en linjeavslutning (\n) felaktigt tillåten efter pilfunktionsargument. Detta har åtgärdats för att överensstämma med ES2015-specifikationen och kod som () \n =>
IE Inget stöd NejOpera Fullständigt stöd 32Safari Fullständigt stöd 10WebView Android Fullt stöd 45Chrome Android Fullständigt stöd 45Firefox Android Fullständigt stöd 22

Anteckningar

Fullt stöd 22

Anteckningar

Anteckningar Den initiala implementeringen av pilfunktioner i Firefox gjorde dem automatiskt strikta. Detta har ändrats från och med Firefox 24. Användningen av "använd strikt"; krävs nu. Anteckningar Före Firefox 39 var en linjeavslutning (\n) felaktigt tillåten efter pilfunktionsargument. Detta har åtgärdats för att överensstämma med ES2015-specifikationen och kod som () \n => () kommer nu att skicka ett SyntaxError i denna och senare versioner.
Opera Android Fullt stöd 32Safari iOS Fullständigt stöd 10Samsung Internet Android Fullt stöd 5.0nodejs Fullt stöd Ja
Chrome Fullt stöd 58Kant?Firefox Fullständigt stöd 52IE Inget stöd NejOpera Fullständigt stöd 45Safari?WebView Android Fullt stöd 58Chrome Android Fullständigt stöd 58Firefox Android Fullständigt stöd 52Opera Android Fullt stöd 43Safari iOS?Samsung Internet Android Fullt stöd 7.0nodejs Fullt stöd Ja
Förklaring Fullt stöd Fullständigt stöd Inget stöd Inget stöd Kompatibilitet okänd Kompatibilitet okänd Se implementeringsnoteringar. Se implementeringsnoteringar.
  • Handledning

En av de mest intressanta delarna av den nya ECMAScript 6-standarden är pilfunktionerna. Pilfunktioner, som namnet antyder, definieras av en ny syntax som använder en pil => . Men förutom sin utmärkta syntax skiljer sig pilfunktioner från traditionella funktioner på andra sätt:

  • Lexikalisk bindning. Värderingar speciella variabler detta , super och argument bestäms inte av hur pilfunktioner anropades, utan av hur de skapades.
  • Oföränderliga detta, super och argument. Värdena för dessa variabler i pilfunktionerna förblir oförändrade genomgående livscykel funktioner.
  • Pilfunktioner kan inte användas som en konstruktor och ger ett fel när de används med den nya operatorn.
  • Otillgänglighet för det "native" värdet för argumentvariabeln.
Det fanns flera skäl för att införa dessa skillnader. Den första är att bindning används ganska ofta i JavaScript. Det är mycket lätt att förlora rätt detta värde när du använder traditionella funktioner, vilket kan leda till oväntade konsekvenser. En annan anledning är att JS-motorer enkelt kommer att kunna optimera exekveringen av pilfunktioner på grund av dessa begränsningar (till skillnad från traditionella funktioner som kan användas som konstruktör och är fria att modifiera speciella variabler).


Obs: Den här artikeln är en sammanställning från en fri översättning av artikeln Understanding ECMAScript 6 arrow functions och en läsning av det senaste utkastet till specifikationen (20 januari 2014 Draft Rev 22).

Syntax Generellt sett ser syntaxen för pilfunktioner ut så här:

Var kul = (x) => x;
Det är väldigt likt liknande syntax i språk som Scala, CoffeeScript och syntaxen för lambda-uttryck från C#.

Syntaxen för pilfunktioner kan variera beroende på hur du deklarerar funktionen. Deklarationen börjar alltid med en lista med argument, följt av en pil och funktionens brödtext. Både argumentlistan och funktionskroppen kan ta olika former, beroende på vad du skriver.

En parameter Att deklarera en pilfunktion som tar ett argument och helt enkelt returnerar det är väldigt enkelt:

Var reflect = värde => värde; // motsvarande var reflect = funktion(värde) (returvärde;)
När en pilfunktion bara har ett argument kan den deklareras utan parentes. Funktionskroppen efter pilen kanske inte heller har några hängslen och får inte innehålla nyckelordet retur.

Flera parametrar Men om du vill deklarera mer än en parameter måste du bifoga parameterlistan inom parentes:

Var summa = (num1, num2) => num1 + num2; // ekvivalent med var summa = function(num1, num2) ( returnera num1 + num2; );
Summafunktionen lägger helt enkelt till två argument. Den enda skillnaden från föregående exempel är närvaron av parenteser och ett kommatecken (precis som i traditionella funktioner).

Inga parametrar På samma sätt måste en funktion utan några argument ha en tom parameterlista inom parentes:

Var summa = () => 1 + 2; // ekvivalent med var summa = function() ( return 1 + 2; );

Traditionell funktionskroppssyntax Du kan använda traditionell funktionssyntax för en pilfunktions brödtext när den innehåller mer än ett uttryck. Det vill säga, linda in funktionen i hängslen och lägg till nyckelordet retur:

Var summa = (num1, num2) => ( returnera num1 + num2; ) // motsvarande var summa = function(num1, num2) ( returnera num1 + num2; );
Funktionens kropp kommer att bearbetas på exakt samma sätt som för klassiska funktioner, förutom att värdena speciella variabler detta, super och argument kommer att utvärderas annorlunda.

Objekt literal Separat bör det nämnas att kroppen i en funktion som inte innehåller krulliga klammerparenteser och som bara returnerar ett objekt literal bör omges av parentes:

Var getTempItem = id => (( id: id, namn: "Temp" )); // motsvarande var getTempItem = function(id) ( return ( id: id, name: "Temp" ) );
Att placera ett objekt bokstavligt inom parentes säger till analysatorn att de krulliga klammerparenteserna inte är början på traditionell syntax för en funktionskropp, utan början på en bokstavlig.

Variabelt antal parametrar Eftersom objektet "native" arguments inte är tillgängligt i en pilfunktion (värdet av argument är lexikalt relaterat till värdet av argumenten för den traditionella funktionen inom vilken pilfunktionen deklarerades), då för pilfunktioner med en variabelt antal parametrar du behöver använda vilomönstret från förstörande mönster. Exempel:

Var getTempItems = (...vila) => vila; // motsvarande var getTempItems = function() ( return .slice.apply(arguments) );

Destruktureringsmall som parameter I den här artikelns syften överväger vi inte att destrukturera mönster - du kan läsa om dem i artikeln Översikt över ECMAScript 6, nästa version av JavaScript, även om denna information är delvis föråldrad.

Som du kan se från föregående exempel, även om pilfunktionen bara har ett argument, måste du fortfarande använda parenteser när du använder förstörande mönster som funktionens enda parameter. Exempel med andra mallar:

Var a = ((a)) => a; var b = ([b]) => b;

Använda pilfunktioner Ange kontext Ett vanligt scenario i JavaScript är att ställa in det korrekta värdet i en funktion (bindning). Eftersom värdet på detta kan ändras, beroende på i vilket sammanhang funktionen exekveras, är det möjligt att av misstag agera på ett objekt när man menade något helt annat. Titta på följande exempel:

Var pageHandler = ( id: "123456" , init: function() ( document.addEventListener("klick", function(event) ( this.doSomething(event.type); // error )); ), doSomething: function( type) ( console.log("Hantering " + typ + " för " + detta.id) ) );
I koden ovan ska pageHandler-objektet hantera klick på sidan. Metoden init() kopplar en hanterare till den önskade händelsen, som internt anropar this.doSomething() . Koden kommer dock inte att fungera korrekt. Referensen till this.doSomething() är inte giltig eftersom den pekar på dokumentobjektet inuti händelsehanteraren istället för den avsedda pageHandler . Om du försöker köra den här koden får du ett felmeddelande eftersom dokumentobjektet inte har en doSomething-metod.

Du kan binda detta värde till pageHandler-objektet med handleEvent eller genom att anropa standardmetoden bind() på funktionen:

Var pageHandler = ( id: "123456" , init: function() ( document.addEventListener("klick", (function(event) ( this.doSomething(event.type); // error )).bind(this)) ; ) , doSomething: function(typ) ( console.log("Hantera " + typ + " för " + detta.id) ) );
Nu fungerar koden som den ska, men den ser krångligare ut. Dessutom, genom att anropa bind(this) varje gång du skapar en ny funktion vars detta värde är kopplat till värdet på pageHandler , men koden fungerar som du tänkt dig.

Pilfunktioner löser problemet på ett mer elegant sätt eftersom de använder lexikal bindning för värdet av detta (samt super och argument ) och dess värde bestäms av värdet av detta på den plats där pilfunktionen skapades. Till exempel:

Var pageHandler = ( id: "123456" , init: function() ( document.addEventListener("klick", händelse => this.doSomething(event.type)); ), doSomething: function(typ) ( console.log( "Hantering " + skriv + " för " + this.id) ) );
I det här exemplet är hanteraren en pilfunktion som anropar this.doSomething() . Värdet på detta kommer att vara detsamma som i funktionen init() och koden i i detta exempel kommer att fungera korrekt, liknande den som använde bind() . Oavsett om anropet till this.doSomething() returnerar ett värde eller inte, behöver uttrycket inuti kroppen av en pilfunktion inte vara inneslutet av klammerparenteser.

Dessutom är exemplet ovan också mer effektivt än att anropa bind() eftersom det är samma som följande kod för webbläsaren:

Var pageHandler = ( id: "123456" , init: function() ( var self = this; document.addEventListener("click", function(event) (retur self.doSomething(event.type) )); ), doSomething: function(type) ( console.log("Hantering " + typ + " för " + detta.id) ) );
Det vill säga skapande förekommer inte ny funktion, som är fallet med bind()-anropet.

"Kasta" sammanhanget mellan flera samtal Självklart kan du kapsla en pilfunktion i en annan och därigenom "kasta" detta värde genom dem:

Var obj = ( arr1: , arr2: ["a", "b", "c"] , sammanfoga: funktion(a, b)( returnera a + "|" + b ), skärningspunkt: function() ( returnera detta .arr1.reduce((summa, v1) => // pilfunktion 1 this.arr2.reduce((summa, v2) => ( // pilfunktion 2 sum.push(this.concatenate(v1, v2)) returnera summa; ) , summa) , ) ) ); var arrSum = obj.intersection();//["1|a", "1|b", "1|c", "2|a", "2|b", "2|c", "3 |a", "3|b", "3|c"]

Använd som argument Den korta syntaxen för pilfunktioner gör dem till idealiska kandidater för att skicka som argument till andra funktionsanrop. Om du till exempel vill sortera en array brukar du skriva något så här:

Var result = values.sort(function(a, b) (retur a - b));
Ganska utförligt för en enkel operation. Jämför med den korta notationen för en pilfunktion:

Var resultat = värden.sort((a, b) => a - b);
Användningen av metoder som array() , map() , reduce() och så vidare kan förenklas med hjälp av funktionssyntaxen för kort pil.

Andra funktioner hos pilfunktioner Även om pilfunktioner skiljer sig från traditionella funktioner, har de några gemensamma funktioner:
  • Typen av operatör kommer att returnera "funktion" för en pilfunktion
  • En pilfunktion är också en instans av funktionen "klass", så instanceof kommer att fungera på samma sätt som med en traditionell funktion
  • Du kan fortfarande använda metoderna call(), application() och bind(), men kom ihåg att de inte påverkar värdet på detta
  • Du kan använda metoden toMethod(), men den kommer inte att ändra värdet på super ( metoden toMethod() introducerades i es6 och täcks inte av den här artikeln).
En betydande skillnad från traditionella funktioner är att ett försök att anropa en pilfunktion med den nya operatorn kommer att orsaka ett körtidsfel Sammanfattning Pilfunktioner är en av de mest intressanta innovationerna i ECMAScript 6, som, med en kortfattad definitionssyntax, kommer att förenkla överföra funktioner som ett parametervärde till en annan funktion.

Kortfattad syntax gör att du kan skriva komplexa saker ännu mer komplext på ett enklare sätt. Så här kommer till exempel identifierargeneratorn att se ut (som ser mycket mer utförlig ut på es5):

Låt idGen = (start = 0, id = start, reset = (newId = start) => id = newId, next = () => id++) => ((återställ, nästa)); låt gen = idGen(100); console.log(gen.next(), gen.next(), gen.reset(10), gen.next());//100 101 10 10
Och lexikal bindning kommer att stänga en av de största källorna till smärta och frustration för utvecklare, och kommer också att förbättra prestandan på grund av optimering på js-motornivå.


Om du vill prova pilfunktioner kan du köra ovanstående exempel i Firefox-konsolen som är på det här ögonblicket(02.2014 FF28) stöder nästan fullt ut pilfunktioner (FF28 beräknar felaktigt värdet på argument ).

Du kan också prova pilfunktioner och andra es6-funktioner i onlineöversättaren Traceur.

Taggar: Lägg till taggar