10. Destruktion
10. Destruktion #
- 10.1. Översikt
- 10.1.1. Objekt destruktion
- 10.1.2. Array destructuring
- 10.1.3. Var kan destruktion användas?
- 10.2. Bakgrund: konstruera data kontra extrahera data
- 10.3. Mönster för destruktion
- 10.3.1. Välj vad du behöver
- 10.4. Hur får mönster tillgång till värderingarnas inre?
- 10.4.1. Objektmönster tvinga värden till objekt
- 10.4.2. Array mönster arbeta med iterables
- 10.5. Standardvärden
- 10.5.1.
undefined
utlöser standardvärden - 10.5.2. Standardvärden beräknas på begäran
- 10.5.3. Standardvärden kan hänvisa till andra variabler i mönstret
- 10.5.4. Standardvärden för mönster
- 10.5.5. Mer komplexa standardvärden
- 10.5.1.
- 10.6. Fler objekt destructuring funktioner
- 10.6.1. Fastighetsvärde stenografi
- 10.6.2. Beräknade fastighetsnycklar
- 10.7. Fler Array destructuring funktioner
- 10.7.1. Elision
- 10.7.2. Vila operatör (
...
)
- 10.8. Du kan tilldela mer än bara variabler
- 10.9. Fallgropar av destruktion
- 10.9.1. Börja inte ett uttalande med en lockig stag
- 10.10. Exempel på destruktion
- 10.10.1. Destructuring returnerade matriser
- 10.10.2. Destructuring returnerade objekt
- 10.10.3. Array-destructuring iterable värden
- 10.10.4. Flera returvärden
- 10.11. Destruktionsalgoritmen
- 10.11.1. Algoritmen
- 10.11.2. Tillämpa algoritmen
10.1 översikt #
Destructuring är ett bekvämt sätt att extrahera flera värden från data lagrade i (eventuellt kapslade) objekt och matriser. Den kan användas på platser som tar emot data (t.ex. den vänstra sidan av en uppgift). Hur man extraherar värdena anges via mönster (läs vidare för exempel).
10.1.1 objekt destructuring #
Destructuring objekt:
Destructuring hjälper till med bearbetning av returvärden:
10.1.2 Array destructuring #
Array destructuring (fungerar för alla iterabla värden):
Destructuring hjälper till med bearbetning av returvärden:
10.1.3 Var kan destruktion användas? #
Destructuring kan användas på följande platser (jag visar Matrismönster för att demonstrera; objektmönster fungerar lika bra):
du kan också förstöra i en for-of
– slinga:
10.2 Bakgrund: konstruera data kontra extrahera data #
för att fullt ut förstå vad destruktion är, låt oss först undersöka dess bredare sammanhang.
JavaScript har operationer för att konstruera data, en egenskap i taget:
samma syntax kan användas för att extrahera data. Återigen, en fastighet i taget:
dessutom finns det syntax för att konstruera flera egenskaper samtidigt, via ett objekt bokstavligt:
före ES6 fanns det ingen motsvarande mekanism för att extrahera data. Det är vad destruktion är – det låter dig extrahera flera egenskaper från ett objekt via ett objektmönster. Till exempel på vänster sida av en uppgift:
du kan också förstöra matriser via mönster:
10.3 Mönster för destruktion #
följande två parter är involverade i destruktion:
- Destructuring source: de data som ska destrueras. Till exempel den högra sidan av en destruktionsuppgift.
- Destructuring target: mönstret som används för destructuring. Till exempel den vänstra sidan av en destruktionsuppgift.
destruktionsmålet är antingen ett av tre mönster:
- uppdragsmål. Till exempel:
x
- ett tilldelningsmål är vanligtvis en variabel. Men i destructuring uppdrag, du har fler alternativ, som jag ska förklara senare.
- objekt mönster. Till exempel:
{ first: "pattern", last: "pattern" }
- delarna av ett objektmönster är egenskaper, egenskapsvärdena är igen mönster (rekursivt).
- Array mönster. Till exempel:
- delarna av ett Matrismönster är element, elementen är igen mönster (rekursivt).
det betyder att du kan bo mönster, godtyckligt djupt:
10.3.1 Välj vad du behöver #
om du förstör ett objekt nämner du bara de egenskaper du är intresserad av:
om du förstör en Array kan du välja att bara extrahera ett prefix:
10.4 Hur får mönster tillgång till värderingarnas inre? #
i en uppgift pattern = someValue
, hur kommer pattern
åt vad som finns inuti someValue
?
10.4.1 Objektmönster tvingar värden till objekt #
objektmönstret tvingar förstörande källor till objekt innan du öppnar egenskaper. Det betyder att det fungerar med primitiva värden:
10.4.1.1 att misslyckas med att objekt-förstöra ett värde #
tvång till objekt utförs inte via Object()
, utan via den interna operationen ToObject()
. De två operationerna hanterar undefined
och null
annorlunda.
Object()
konverterar primitiva värden till wrapper-objekt och lämnar objekt orörda:
It also converts undefined
and null
to empty objects:
In contrast, ToObject()
throws a TypeError
if it encounters undefined
or null
. Therefore, the following destructurings fail, even before destructuring accesses any properties:
som en konsekvens kan du använda det tomma objektmönstret {}
för att kontrollera om ett värde är tvingande för ett objekt. Som vi har sett är bara undefined
och null
inte:
parenteserna runt uttrycken är nödvändiga eftersom uttalanden inte får börja med lockiga hängslen i JavaScript (detaljer förklaras senare).
10.4.2 Array mönster arbeta med iterables #
Array destructuring använder en iterator för att komma till elementen i en källa. Därför kan du Array-destructure något värde som är iterable. Låt oss titta på exempel på iterabla värden.
strängar är iterabla:
glöm inte att iteratorn över strängar returnerar Kodpunkter (”Unicode-tecken”, 21 bitar), inte kodenheter (”JavaScript-tecken”, 16 bitar). (För mer information om Unicode, se kapitlet ” kapitel 24. Unicode och JavaScript ”i”talande JavaScript”.) Till exempel:
du kan inte komma åt elementen i en uppsättning via index, men du kan göra det via en iterator. Därför fungerar array destructuring för uppsättningar:
iteratorn Set
returnerar alltid element i den ordning de infogades i, varför resultatet av den tidigare förstöringen alltid är detsamma.
10.4.2.1 misslyckas med att array-destructure ett värde #
ett värde är iterabelt om det har en metod vars nyckel är Symbol.iterator
som returnerar ett objekt. Array-destructuring kastar en TypeError
om värdet som ska destrueras inte är iterabelt:
TypeError
kastas redan innan du öppnar element i iterable, vilket innebär att du kan använda det tomma Matrismönstret för att kontrollera om ett värde är iterabelt:
10.5 standardvärden #
standardvärden är en valfri funktion i mönster. De ger en reserv om ingenting Finns i källan. Om en del (en objektegenskap eller ett matriselement) inte har någon matchning i källan matchas den mot:
- dess standardvärde (om det anges; det är valfritt)
-
undefined
(annars)
Låt oss titta på ett exempel. I följande destruktion har elementet vid index 0 ingen matchning på höger sida. Därför fortsätter destruktionen genom att matcha x
mot 3, vilket leder till att x
sätts till 3.
du kan också använda standardvärden i objektmönster:
10.5.1 undefined
utlöser standardvärden #
standardvärden används också om en del har en matchning och den matchningen är undefined
:
motiveringen för detta beteende förklaras i nästa kapitel, i avsnittet om parameterns standardvärden.
10.5.2 standardvärden beräknas på begäran #
själva standardvärdena beräknas endast när de behövs. Med andra ord, denna förstörelse:
motsvarar:
du kan observera att om du använder console.log()
:
In the second destructuring, the default value is not triggered and log()
is not called.
10.5.3 Default values can refer to other variables in the pattern #
A default value can refer to any variable, including other variables in the same pattern:
orderfrågor: variablerna x
och y
deklareras från vänster till höger och producerar en ReferenceError
om de nås före deklarationerna:
10.5.4 standardvärden för mönster #
hittills har vi bara sett standardvärden för variabler, men du kan också associera dem med mönster:
vad betyder detta? Återkalla regeln för standardvärden: om en del inte har någon matchning i källan fortsätter förstöringen med standardvärdet.
elementet vid index 0 har ingen matchning, varför destruktionen fortsätter med:
du kan lättare se varför saker fungerar på detta sätt om du ersätter mönstret { prop: x }
med variabeln pattern
:
10.5.5 mer komplexa standardvärden #
Låt oss vidare undersöka standardvärden för mönster. I följande exempel tilldelar vi ett värde till x
via standardvärdet { prop: 123 }
:
eftersom Matriselementet vid index 0 inte har någon matchning på höger sida fortsätter destruktionen enligt följande och x
är satt till 123.
x
tilldelas dock inte ett värde på detta sätt om den högra sidan har ett element vid index 0, för då utlöses inte standardvärdet.
i detta fall fortsätter destruktionen med:
om du vill att x
ska vara 123 om antingen objektet eller egenskapen saknas måste du ange ett standardvärde för x
själv:
här fortsätter destruktionen enligt följande, oberoende av om höger sida är eller
.
10.6 fler objekt destructuring funktioner #
10.6.1 fastighetsvärde shorthands #
fastighetsvärde shorthands är en funktion av objekt bokstav: Om egenskapsvärdet är en variabel som har samma namn som egenskapsnyckeln kan du utelämna nyckeln. Detta fungerar för destruktion, för:
du kan också kombinera fastighetsvärde shorthands med standardvärden:
10.6.2 beräknade egenskapsnycklar #
beräknade egenskapsnycklar är en annan bokstavlig funktion för objekt som också fungerar för destruktion. Du kan ange nyckeln till en fastighet via ett uttryck, om du lägger den i hakparenteser:
med beräknade egenskapsnycklar kan du förstöra egenskaper vars nycklar är symboler:
10.7 fler Array destructuring funktioner #
10.7.1 Elision #
Elision låter dig använda syntaxen för Array ”hål” för att hoppa över element under destructuring:
10.7.2 Vila operatör (...
) #
resten operatören kan du extrahera de återstående elementen i en iterable i en Array. Om den här operatören används i ett Matrismönster måste det komma sist:
om operatören inte kan hitta några element matchar den sin operand mot den tomma matrisen. Det betyder att det aldrig producerar undefined
eller null
. Till exempel:
resten operatörens operand behöver inte vara en variabel, du kan också använda mönster:
resten operatören utlöser följande destruktion:
10.8 Du kan tilldela mer än bara variabler #
om du tilldelar via destruktion kan varje tilldelningsmål vara allt som är tillåtet på vänster sida av en normal tilldelning.
till exempel en hänvisning till en egenskap (obj.prop
):
eller en hänvisning till ett arrayelement (arr
):
du kan också tilldela objektegenskaper och matriselement via operatören rest (...
):
om du deklarerar variabler eller definierar parametrar via destruktion måste du använda enkla identifierare, du kan inte referera till objektegenskaper och arrayelement.
10.9 fallgropar av destructuring #
det finns två saker att vara uppmärksam på när du använder destructuring:
- du kan inte starta ett uttalande med en lockig stag.
- under destruktion kan du antingen deklarera variabler eller tilldela dem, men inte båda.
de följande två avsnitten innehåller detaljerna.
10.9.1 Starta inte ett uttalande med en lockig stag #
eftersom kodblock börjar med en lockig stag, får uttalanden inte börja med en. Detta är olyckligt när du använder objektförstöring i en uppgift:
arbetet är att sätta hela uttrycket inom parentes:
följande syntax fungerar inte:
med let
, var
och const
orsakar lockiga hängslen aldrig problem:
10.10 Exempel på destructuring #
Låt oss börja med några mindre exempel.
for-of
loop stöder destruktion:
du kan använda destructuring för att byta värden. Det är något som motorer kan optimera, så att ingen Array skulle skapas.
du kan använda destructuring för att dela en Array:
10.10.1 Destructuring returnerade matriser #
vissa inbyggda JavaScript-operationer returnerar matriser. Destructuring hjälper till att bearbeta dem:
om du bara är intresserad av grupperna (och inte i hela matchen, all
) kan du använda elision för att hoppa över arrayelementet vid index 0:
exec()
returnerar null
om det reguljära uttrycket inte matchar. Tyvärr kan du inte hantera null
via standardvärden, varför du måste använda or-operatören (||
) i det här fallet:
Array.prototype.split()
returnerar en Array. Därför är destruktion användbar om du är intresserad av elementen, inte matrisen:
10.10.2 Destructuring returned objects #
Destructuring är också användbart för att extrahera data från objekt som returneras av funktioner eller metoder. Till exempel returnerar iteratormetoden next()
ett objekt med två egenskaper, done
och value
. Följande kod loggar alla element i Array arr
via iteratorn iter
. Destruktion används i linje A.
10.10.3 Array-destructuring iterable values #
Array-destructuring fungerar med alla iterabla värden. Det är ibland användbart:
10.10.4 flera returvärden #
för att se användbarheten av flera returvärden, låt oss implementera en funktion findElement(a, p)
som söker efter det första elementet i matrisen a
för vilken funktionen p
returnerar true
. Frågan är: vad ska findElement()
återvända? Ibland är man intresserad av själva elementet, ibland i sitt index, ibland i båda. Följande implementering returnerar båda.
funktionen itererar över alla element i array
, via Arraymetoden entries()
, som returnerar en iterabel över par (rad a). Delarna av paren nås via destruktion.
Låt oss använda findElement()
:
flera ECMAScript 6 funktioner tillät oss att skriva mer kortfattad kod: återuppringningen är en pilfunktion; returvärdet förstörs via ett objektmönster med fastighetsvärde stenografi.
på grund av index
och element
hänvisar också till egenskapsnycklar, den ordning som vi nämner dem spelar ingen roll. Vi kan byta dem och ingenting förändras:
vi har framgångsrikt hanterat fallet med att behöva både index och element. Vad händer om vi bara är intresserade av en av dem? Det visar sig att tack vare ECMAScript 6 kan vår implementering också ta hand om det. Och den syntaktiska overhead jämfört med funktioner med enstaka returvärden är minimal.
varje gång extraherar vi bara värdet av den enda egenskapen som vi behöver.
10.11 destructuring algorithm #
detta avsnitt tittar på destructuring från en annan vinkel: som en rekursiv mönstermatchningsalgoritm.
i slutet använder jag algoritmen för att förklara skillnaden mellan följande två funktionsdeklarationer.
10.11.1 algoritmen #
en destruktionsuppgift ser ut så här:
vi vill använda pattern
för att extrahera data från value
. Jag ska nu beskriva en algoritm för att göra det, vilket är känt i funktionell programmering som mönstermatchning (kort: matchning). Algoritmen anger operatören ←
(”matcha mot”) för destruktionstilldelning som matchar en pattern
mot en value
och tilldelar variabler medan du gör det:
algoritmen specificeras via rekursiva regler som tar isär båda operanderna för operatören ←
. Den deklarativa notationen kan ta lite att vänja sig, men det gör specifikationen av algoritmen mer kortfattad. Varje regel har två delar:
- huvudet (första raden) beskriver villkoret som utlöser regeln.
- kroppen (återstående rader) beskriver vad som händer om regeln utlöses.
Låt oss titta på ett exempel:
- (2c)
{key: "pattern", "properties"} ← obj
- (2e)
{} ← obj
( inga egenskaper kvar)
i regel (2c) betyder huvudet att denna regel exekveras om det finns ett objektmönster med minst en egenskap och noll eller flera återstående egenskaper. Detta mönster matchas mot ett värde obj
. Effekten av denna regel är att exekveringen fortsätter med att egenskapsvärdesmönstret matchas mot obj.key
och de återstående egenskaperna matchas mot obj
.
i regel (2e) betyder huvudet att denna regel exekveras om det tomma objektmönstret {}
matchas mot ett värde obj
. Då finns det inget att göra.
när algoritmen anropas kontrolleras reglerna uppifrån och ned och endast den första regeln som är tillämplig exekveras.
jag visar bara algoritmen för destruktionstilldelning. Destructuring variable declarations och destructuring parameterdefinitioner fungerar på samma sätt.
jag täcker inte avancerade funktioner (beräknade egenskapsnycklar; fastighetsvärde stenografi; objektegenskaper och matriselement som tilldelningsmål), antingen. Bara grunderna.
10.11.1.1 mönster #
ett mönster är antingen:
- en variabel:
x
- ett objektmönster:
{"properties"}
- ett Matrismönster:
var och en av följande avsnitt beskriver ett av dessa tre fall.
följande tre avsnitt anger hur dessa tre fall ska hanteras. Varje avsnitt innehåller en eller flera numrerade regler.
10.11.1.2 variabel #
- (1)
x ← value
(inklusiveundefined
ochnull
)
10.11.1.3 objekt mönster #
- (2a)
{"properties"} ← undefined
- (2b)
{"properties"} ← null
- (2c)
{key: "pattern", "properties"} ← obj
- (2d)
{key: "pattern" = default_value, "properties"} ← obj
- (2e)
{} ← obj
( inga egenskaper kvar)
10.11.1.4 Array mönster #
Array mönster och iterable. Algoritmen för Array destructuring börjar med ett Arraymönster och en iterabel:
- (3a)
← non_iterable
assert(!isIterable(non_iterable))
- (3b)
← iterable
assert(isIterable(iterable))
Hjälparfunktion:
Array element och iterator. Algoritmen fortsätter med elementen i mönstret (vänster sida av pilen) och iteratorn som erhölls från den iterabla (höger sida av pilen).
- (3c)
"pattern", "elements" ← iterator
- (3d)
"pattern" = default_value, "elements" ← iterator
- (3e)
, "elements" ← iterator
(hål, elision)
- (3f)
..."pattern" ← iterator
( alltid sista delen!)
- (3g)
← iterator
( inga element kvar)
Hjälparfunktion:
10.11.2 genom att använda algoritmen #
i ECMAScript 6 kan du simulera namngivna parametrar om den som ringer använder ett objekt bokstavligt och callee använder destruktion. Denna simulering förklaras i detalj i kapitlet om parameterhantering. Följande kod visar ett exempel: funktion move1()
har två namngivna parametrar, x
och y
:
det finns tre standardvärden i rad A:
- de två första standardvärdena låter dig utelämna
x
ochy
. - det tredje standardvärdet låter dig ringa
move1()
utan parametrar (som i sista raden).
men varför skulle du definiera parametrarna som i föregående kodavsnitt? Varför inte enligt följande-vilket också är helt lagligt ES6-kod?
för att se varför move1()
är korrekt, låt oss använda båda funktionerna för två exempel. Innan vi gör det, låt oss se hur överföringen av parametrar kan förklaras via matchning.
10.11.2.1 Bakgrund: passande parametrar via matchning #
för funktionssamtal matchas formella parametrar (inuti funktionsdefinitioner) mot faktiska parametrar (inuti funktionssamtal). Ta till exempel följande funktionsdefinition och följande funktionsanrop.
parametrarna a
och b
ställs in på samma sätt som följande destruktion.
10.11.2.2 använda move2()
#
Låt oss undersöka hur destruktion fungerar för move2()
.
exempel 1. move2()
leder till denna förstörelse:
det enda Matriselementet på vänster sida har ingen matchning på höger sida, varför {x,y}
matchas mot standardvärdet och inte mot data från höger sida (regler 3b, 3d):
den vänstra sidan innehåller fastighetsvärde shorthands, det är en förkortning för:
denna destruktion leder till följande två uppdrag (regler 2C, 1):
exempel 2. Låt oss undersöka funktionsanropet move2({z:3})
vilket leder till följande förstöring:
det finns ett arrayelement vid index 0 på höger sida. Därför ignoreras standardvärdet och nästa steg är (regel 3d):
det leder till att både x
och y
sätts till undefined
, vilket inte är vad vi vill ha.
10.11.2.3 användning move1()
#
låt oss försöka move1()
.
exempel 1: move1()
vi har inte ett arrayelement vid index 0 på höger sida och använder standardvärdet (regel 3d):
den vänstra sidan innehåller fastighetsvärde shorthands, vilket innebär att denna destruktion motsvarar:
varken egendom x
eller egendom y
har en matchning på höger sida. Därför används standardvärdena och följande destruktioner utförs nästa (regel 2d):
det leder till följande uppdrag (regel 1):
exempel 2: move1({z:3})
det första elementet i Matrismönstret har en matchning på höger sida och den matchen används för att fortsätta förstöra (regel 3d):
som i Exempel 1 finns det inga egenskaper x
och y
på höger sida och standardvärdena används:
10.11.2.4 slutsats #
exemplen visar att standardvärden är en egenskap hos mönsterdelar (objektegenskaper eller arrayelement). Om en del inte har någon matchning eller matchas mot undefined
används standardvärdet. Det vill säga mönstret matchas mot standardvärdet istället.