10. Destrutturazione
10. Destrutturazione #
- 10.1. Panoramica
- 10.1.1. Destrutturazione degli oggetti
- 10.1.2. Destrutturazione dell’array
- 10.1.3. Dove si può usare la destrutturazione?
- 10.2. Background: costruire dati contro estrarre dati
- 10.3. Modelli per la destrutturazione
- 10.3.1. Scegli quello che ti serve
- 10.4. In che modo i modelli accedono alle interiora dei valori?
- 10.4.1. I modelli oggetto costringono i valori agli oggetti
- 10.4.2. I modelli di array funzionano con iterabili
- 10.5. Valori predefiniti
- 10.5.1.
undefined
attiva i valori predefiniti - 10.5.2. I valori predefiniti vengono calcolati su richiesta
- 10.5.3. I valori predefiniti possono riferirsi ad altre variabili nel modello
- 10.5.4. Valori predefiniti per i modelli
- 10.5.5. Valori predefiniti più complessi
- 10.5.1.
- 10.6. Altre funzioni di destrutturazione degli oggetti
- 10.6.1. Proprietà valore stenografie
- 10.6.2. Chiavi di proprietà calcolate
- 10.7. Altre funzionalità di destrutturazione dell’array
- 10.7.1. Elision
- 10.7.2. Operatore di riposo (
...
)
- 10.8. È possibile assegnare a più di semplici variabili
- 10.9. Insidie di destrutturazione
- 10.9.1. Non iniziare una dichiarazione con una parentesi graffa
- 10.10. Esempi di destrutturazione
- 10.10.1. Destrutturazione degli array restituiti
- 10.10.2. Destrutturazione degli oggetti restituiti
- 10.10.3. Array-destrutturazione dei valori iterabili
- 10.10.4. Valori di ritorno multipli
- 10.11. L’algoritmo di destrutturazione
- 10.11.1. L’algoritmo
- 10.11.2. Applicazione dell’algoritmo
10.1 Panoramica #
La destrutturazione è un modo conveniente per estrarre più valori dai dati memorizzati in oggetti e array (eventualmente nidificati). Può essere utilizzato in posizioni che ricevono dati (come il lato sinistro di un’assegnazione). Come estrarre i valori è specificato tramite pattern (continua a leggere per gli esempi).
10.1.1 Destrutturazione degli oggetti #
Destrutturazione degli oggetti:
const
obj
=
{
first
:
'Jane'
,
last
:
'Doe'
};
const
{
first
:
f
,
last
:
l
}
=
obj
;
// f = 'Jane'; l = 'Doe'
// {prop} is short for {prop: prop}
const
{
first
,
last
}
=
obj
;
// first = 'Jane'; last = 'Doe'
Destrutturazione aiuta con l’elaborazione dei valori di ritorno:
const
obj
=
{
foo
:
123
};
const
{
writable
,
configurable
}
=
Object
.
getOwnPropertyDescriptor
(
obj
,
'foo'
);
console
.
log
(
writable
,
configurable
);
// true true
10.1.2 Array destrutturazione #
Array destrutturazione (funziona per tutti iterable valori):
const
iterable
=
;
const
=
iterable
;
// x = 'a'; y = 'b'
Destrutturazione aiuta con l’elaborazione dei valori di ritorno:
const
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
'2999-12-31'
);
10.1.3 Dove è possibile destrutturazione essere utilizzato? #
La destrutturazione può essere utilizzata nelle seguenti posizioni (sto mostrando modelli di array per dimostrare; i modelli di oggetti funzionano altrettanto bene):
// Variable declarations:
const
=
;
let
=
;
var
=
;
// Assignments:
=
;
// Parameter definitions:
function
f
()
{
···
}
f
();
Puoi anche destrutturare in un ciclo for-of
:
const
arr
=
;
for
(
const
of
arr
.
entries
())
{
console
.
log
(
index
,
element
);
}
// Output:
// 0 a
// 1 b
10.2 Background: Costruire dati contro estrarre dati #
Per comprendere appieno cos’è la destrutturazione, esaminiamo prima il suo contesto più ampio.
JavaScript ha operazioni per la costruzione di dati, una proprietà alla volta:
const
obj
=
{};
obj
.
first
=
'Jane'
;
obj
.
last
=
'Doe'
;
La stessa sintassi può essere utilizzata per estrarre i dati. Ancora una volta, una proprietà alla volta:
const
f
=
obj
.
first
;
const
l
=
obj
.
last
;
Inoltre, esiste una sintassi per costruire più proprietà contemporaneamente, tramite un oggetto letterale:
const
obj
=
{
first
:
'Jane'
,
last
:
'Doe'
};
Prima di ES6, non esisteva un meccanismo corrispondente per l’estrazione dei dati. Questo è ciò che è la destrutturazione: consente di estrarre più proprietà da un oggetto tramite un modello di oggetto. Ad esempio, sul lato sinistro di un incarico:
const
{
first
:
f
,
last
:
l
}
=
obj
;
È anche possibile destrutturare gli array tramite modelli:
const
=
;
// x = 'a'; y = 'b'
10.3 Modelli per destrutturazione #
Le seguenti due parti sono coinvolte nella destrutturazione:
- Fonte di destrutturazione: i dati da destrutturare. Ad esempio, il lato destro di un’assegnazione destrutturazione.
- Destinazione destrutturazione: il modello utilizzato per la destrutturazione. Ad esempio, il lato sinistro di un’assegnazione destrutturante.
L’obiettivo di destrutturazione è uno dei tre pattern:
- Obiettivo assegnazione. Ad esempio:
x
- Un obiettivo di assegnazione è di solito una variabile. Ma nel destrutturare l’assegnazione, hai più opzioni, come spiegherò più tardi.
- Modello oggetto. Ad esempio:
{ first: "pattern", last: "pattern" }
- Le parti di un modello di oggetto sono proprietà, i valori delle proprietà sono di nuovo modelli (ricorsivamente).
- Modello di matrice. Ad esempio:
- Le parti di un modello di matrice sono elementi, gli elementi sono di nuovo modelli (ricorsivamente).
Ciò significa che è possibile nidificare modelli, arbitrariamente profondamente:
const
obj
=
{
a
:
,
b
:
true
};
const
{
a
:
}
=
obj
;
// f = 123
10.3.1 Scegliere ciò che è necessario #
Se si destructure un oggetto, si menziona solo le proprietà che si sono interessati:
const
{
x
:
x
}
=
{
x
:
7
,
y
:
3
};
// x = 7
Se si destructure un Array, è possibile scegliere di estrarre un prefisso:
const
=
;
// x='a'; y='b';
10.4 Come fare modelli di accesso le interiora di valori? #
In un’assegnazione pattern = someValue
, in che modo pattern
accede a cosa c’è dentro someValue
?
10.4.1 I pattern oggetto costringono i valori agli oggetti #
Il pattern oggetto costringe le sorgenti di destrutturazione agli oggetti prima di accedere alle proprietà. Ciò significa che funziona con valori primitivi:
const
{
length
:
len
}
=
'abc'
;
// len = 3
const
{
toString
:
s
}
=
123
;
// s = Number.prototype.toString
10.4.1.1 Non riuscendo a object-destructure un valore #
La coercizione all’oggetto non viene eseguita tramite Object()
, ma tramite l’operazione interna ToObject()
. Le due operazioni gestiscono undefined
e null
in modo diverso.
Object()
converte i valori primitivi in oggetti wrapper e lascia gli oggetti intatti:
> typeof Object('abc')'object'> var obj = {};> Object(obj) === objtrue
It also converts undefined
and null
to empty objects:
> Object(undefined){}> Object(null){}
In contrast, ToObject()
throws a TypeError
if it encounters undefined
or null
. Therefore, the following destructurings fail, even before destructuring accesses any properties:
const
{
prop
:
x
}
=
undefined
;
// TypeError
const
{
prop
:
y
}
=
null
;
// TypeError
Di conseguenza, è possibile utilizzare il modello di oggetto vuoto {}
per verificare se un valore è coercibile a un oggetto. Come abbiamo visto, solo undefined
e null
non lo sono:
({}
=
);
// OK, Arrays are coercible to objects
({}
=
'abc'
);
// OK, strings are coercible to objects
({}
=
undefined
);
// TypeError
({}
=
null
);
// TypeError
Le parentesi attorno alle espressioni sono necessarie perché le istruzioni non devono iniziare con parentesi graffe in JavaScript (i dettagli sono spiegati in seguito).
10.4.2 I pattern Array funzionano con iterables #
La destrutturazione dell’array utilizza un iteratore per raggiungere gli elementi di una sorgente. Pertanto, è possibile destrutturare qualsiasi valore iterabile. Diamo un’occhiata ad esempi di valori iterabili.
Le stringhe sono iterabili:
const
=
'abc'
;
// x='a'; y=
Non dimenticare che l’iteratore su stringhe restituisce punti di codice (“caratteri Unicode”, 21 bit), non unità di codice (“caratteri JavaScript”, 16 bit). (Per ulteriori informazioni su Unicode, consultare il capitolo ” Capitolo 24. Unicode e JavaScript ” in “Parlando JavaScript”.) Per esempio:
const
=
'a\uD83D\uDCA9c'
;
// x='a'; y='\uD83D\uDCA9'; z='c'
Non è possibile accedere agli elementi di un set tramite indici, ma è possibile farlo tramite un iteratore. Pertanto, la destrutturazione dell’array funziona per gli insiemi:
const
=
new
Set
();
// x='a'; y='b';
L’iteratore Set
restituisce sempre gli elementi nell’ordine in cui sono stati inseriti, motivo per cui il risultato della precedente destrutturazione è sempre lo stesso.
10.4.2.1 Non riuscire a destrutturare un valore #
Un valore è iterabile se ha un metodo la cui chiave è Symbol.iterator
che restituisce un oggetto. Array-destrutturazione genera un TypeError
se il valore da destrutturare non è iterabile:
let
x
;
=
;
// OK, Arrays are iterable
=
'abc'
;
// OK, strings are iterable
=
{
*
()
{
yield
1
}
};
// OK, iterable
=
{};
// TypeError, empty objects are not iterable
=
undefined
;
// TypeError, not iterable
=
null
;
// TypeError, not iterable
Il TypeError
viene generata anche prima di accedere a elementi di iterable, il che significa che è possibile utilizzare l’Array vuoto pattern per verificare se un valore è iterable:
=
{};
// TypeError, empty objects are not iterable
=
undefined
;
// TypeError, not iterable
=
null
;
// TypeError, not iterable
10.5 i valori di Default #
valori di Default sono una funzione opzionale di modelli. Forniscono un fallback se non viene trovato nulla nella fonte. Se una parte (una proprietà dell’oggetto o un elemento dell’array) non ha corrispondenza nell’origine, viene confrontata con:
- il suo valore predefinito (se specificato; è facoltativo)
-
undefined
(altrimenti)
Diamo un’occhiata a un esempio. Nella seguente destrutturazione, l’elemento all’indice 0 non ha corrispondenza sul lato destro. Pertanto, la destrutturazione continua facendo corrispondere x
a 3, il che porta a x
impostato su 3.
const
=
;
// x = 3; y = undefined
È inoltre possibile utilizzare i valori predefiniti nei modelli di oggetti:
const
{
foo
:
x
=
3
,
bar
:
y
}
=
{};
// x = 3; y = undefined
10.5.1 undefined
attiva i valori predefiniti #
I valori predefiniti vengono utilizzati anche se una parte ha una corrispondenza e tale corrispondenza è undefined
:
const
=
;
// x = 1
const
{
prop
:
y
=
2
}
=
{
prop
:
undefined
};
// y = 2
La logica di questo comportamento è spiegata nel prossimo capitolo, nella sezione sui valori predefiniti dei parametri.
10.5.2 I valori predefiniti vengono calcolati su richiesta #
I valori predefiniti vengono calcolati solo quando sono necessari. In altre parole, questa destrutturazione:
const
{
prop
:
y
=
someFunc
()}
=
someValue
;
è equivalente a:
let
y
;
if
(
someValue
.
prop
===
undefined
)
{
y
=
someFunc
();
}
else
{
y
=
someValue
.
prop
;
}
Si può osservare che, se si utilizza console.log()
:
> function log(x) { console.log(x); return 'YES' }> const = ;> a'YES'> const = ;> b123
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:
const
=
;
// x=3; y=3
const
=
;
// x=7; y=7
const
=
;
// x=7; y=2
Tuttavia, l’ordine è importante: le variabili x
e y
sono dichiarati da sinistra a destra e produrre un ReferenceError
se sono visitati prima che le loro dichiarazioni:
const
=
;
// ReferenceError
10.5.4 i valori di Default per i modelli di #
finora abbiamo visto solo i valori di default per le variabili, ma si può anche associare con modelli:
const
=
;
che Cosa significa questo? Richiamare la regola per i valori predefiniti: se una parte non ha corrispondenza nell’origine, la destrutturazione continua con il valore predefinito.
L’elemento con indice 0 non ha corrispondenza, che è il motivo per cui destrutturazione continua con:
const
{
prop
:
x
}
=
{};
// x = undefined
Si può vedere più facilmente perché le cose funzionano in questo modo, se si sostituisce il modello { prop: x }
con la variabile pattern
:
const
=
;
10.5.5 Più complessi i valori di default #
andiamo a esplorare ulteriormente i valori di default per i modelli. Nell’esempio seguente, assegniamo un valore a x
tramite il valore predefinito { prop: 123 }
:
const
=
;
Poiché l’elemento dell’array all’indice 0 non ha corrispondenza sul lato destro, la destrutturazione continua come segue e x
è impostato su 123.
const
{
prop
:
x
}
=
{
prop
:
123
};
// x = 123
Tuttavia, x
non viene assegnato un valore in questo modo se il lato destro ha un elemento all’indice 0, perché il valore predefinito non viene attivato.
const
=
;
In questo caso, la destrutturazione continua con:
const
{
prop
:
x
}
=
{};
// x = undefined
Quindi, se vuoi x
da 123 se l’oggetto o la proprietà non è presente, è necessario specificare un valore predefinito per x
stesso:
const
=
;
Qui, destrutturazione continua come segue, indipendentemente dal fatto che la destra è o
.
const
{
prop
:
x
=
123
}
=
{};
// x = 123
10.6 Altre caratteristiche di destrutturazione degli oggetti #
10.6.1 Proprietà valore stenografie #
Proprietà valore stenografie sono una caratteristica di oggetti letterali: Se il valore della proprietà è una variabile che ha lo stesso nome della chiave di proprietà, è possibile omettere la chiave. Questo funziona anche per la destrutturazione:
const
{
x
,
y
}
=
{
x
:
11
,
y
:
8
};
// x = 11; y = 8
// Same as:
const
{
x
:
x
,
y
:
y
}
=
{
x
:
11
,
y
:
8
};
È inoltre possibile combinare proprietà valore abbreviazioni con valori predefiniti:
const
{
x
,
y
=
1
}
=
{};
// x = undefined; y = 1
10.6.2 Le chiavi di proprietà calcolate #
Le chiavi di proprietà calcolate sono un’altra caratteristica letterale dell’oggetto che funziona anche per la destrutturazione. È possibile specificare la chiave di una proprietà tramite un’espressione, se la si mette tra parentesi quadre:
const
FOO
=
'foo'
;
const
{
:
f
}
=
{
foo
:
123
};
// f = 123
Calcolate proprietà dei tasti consente di destructure proprietà le cui chiavi sono i simboli:
// Create and destructure a property whose key is a symbol
const
KEY
=
Symbol
();
const
obj
=
{
:
'abc'
};
const
{
:
x
}
=
obj
;
// x = 'abc'
// Extract Array.prototype
const
{
:
func
}
=
;
console
.
log
(
typeof
func
);
// function
10.7 Più Array destrutturazione caratteristiche #
10.7.1 Elisione #
Elisione consente di utilizzare la sintassi di una Matrice di “buchi” per ignorare gli elementi durante la destrutturazione:
const
=
;
// x = 'c'; y = 'd'
10.7.2 Resto dell’operatore (...
) #
Il resto dell’operatore, consente di estrarre i restanti elementi di un iterable in un Array. Se questo operatore viene utilizzato all’interno di un modello di matrice, deve venire ultimo:
const
=
;
// x='a'; y=
Se l’operatore non riesce a trovare alcun elemento, corrisponde al suo operando contro l’array vuoto. Cioè, non produce mai undefined
o null
. Per esempio:
const
=
;
// x='a'; y=undefined; z=
L’operando di tutto il resto operatore non deve essere una variabile, è possibile utilizzare i modelli, troppo:
const
]
=
;
// x = 'a'; y = 'b'; z = 'c'
Il resto operatore attiva il seguente destrutturazione:
=
10.8 È possibile assegnare a più di semplici variabili #
Se si assegna tramite destrutturazione, ogni destinazione di assegnazione può essere tutto ciò che è consentito sul lato sinistro di un’assegnazione normale.
Ad esempio, un riferimento a una proprietà (obj.prop
):
const
obj
=
{};
({
foo
:
obj
.
prop
}
=
{
foo
:
123
});
console
.
log
(
obj
);
// {prop:123}
O un riferimento a un elemento di matrice(arr
):
const
arr
=
;
({
bar
:
arr
}
=
{
bar
:
true
});
console
.
log
(
arr
);
//
È inoltre possibile assegnare alle proprietà dell’oggetto e agli elementi dell’array tramite l’operatore rest (...
):
const
obj
=
{};
=
;
// first = 'a'; obj.prop =
Se si dichiarano variabili o si definiscono parametri tramite destrutturazione, è necessario utilizzare identificatori semplici, non è possibile fare riferimento alle proprietà dell’oggetto e agli elementi dell’array.
10.9 Insidie di destrutturazione #
Ci sono due cose da tenere a mente quando si utilizza destrutturazione:
- Non puoi iniziare una dichiarazione con una parentesi graffa.
- Durante la destrutturazione, puoi dichiarare variabili o assegnarle, ma non entrambe.
Le prossime due sezioni contengono i dettagli.
10.9.1 Non avviare un’istruzione con una parentesi graffa #
Poiché i blocchi di codice iniziano con una parentesi graffa, le istruzioni non devono iniziare con una. Questo è un peccato quando si utilizza l’oggetto destrutturazione in un’assegnazione:
{
a
,
b
}
=
someObject
;
// SyntaxError
La soluzione è mettere la completa espressione in parentesi:
({
a
,
b
}
=
someObject
);
// OK
La seguente sintassi non funziona:
({
a
,
b
})
=
someObject
;
// SyntaxError
Con let
, var
e const
, le parentesi graffe non causare problemi:
const
{
a
,
b
}
=
someObject
;
// OK
10.10 Esempi di destrutturazione #
Iniziamo con alcuni esempi più piccoli.
Il ciclo for-of
supporta la destrutturazione:
const
map
=
new
Map
().
set
(
false
,
'no'
).
set
(
true
,
'yes'
);
for
(
const
of
map
)
{
console
.
log
(
key
+
' is '
+
value
);
}
È possibile utilizzare la destrutturazione per scambiare i valori. Questo è qualcosa che i motori potrebbero ottimizzare, in modo che non venga creato alcun Array.
=
;
È possibile utilizzare la destrutturazione per dividere un array:
const
=
;
// first = 'a'; rest =
10.10.1 Destrutturazione degli array restituiti #
Alcune operazioni JavaScript integrate restituiscono gli array. Destrutturazione aiuta con l’elaborazione di loro:
const
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
'2999-12-31'
);
Se si è interessati solo a gruppi (e non per l’intero match, all
), è possibile utilizzare elisione di saltare l’elemento dell’array con indice 0:
const
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
'2999-12-31'
);
exec()
restituisce null
se l’espressione regolare non corrisponde. Sfortunatamente, non è possibile gestire null
tramite i valori predefiniti, motivo per cui è necessario utilizzare l’operatore Or (||
) in questo caso:
const
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
someStr
)
||
;
Array.prototype.split()
restituisce un Array. Pertanto, la destrutturazione è utile se sei interessato agli elementi, non all’Array:
const
cells
=
'Jane\tDoe\tCTO'
const
=
cells
.
split
(
'\t'
);
console
.
log
(
firstName
,
lastName
,
title
);
10.10.2 Destrutturazione oggetti restituiti #
Destrutturazione è utile anche per l’estrazione di dati da oggetti che vengono restituiti da funzioni o metodi. Ad esempio, il metodo iteratore next()
restituisce un oggetto con due proprietà, done
e value
. Il codice seguente registra tutti gli elementi dell’Array arr
tramite l’iteratore iter
. La destrutturazione è utilizzata nella linea A.
const
arr
=
;
const
iter
=
arr
();
while
(
true
)
{
const
{
done
,
value
}
=
iter
.
next
();
// (A)
if
(
done
)
break
;
console
.
log
(
value
);
}
10.10.3 Array-destrutturazione valori iterabili #
Array-destrutturazione funziona con qualsiasi valore iterabile. Questo è occasionalmente utile:
const
=
new
Set
().
add
(
'a'
).
add
(
'b'
);
// x = 'a'; y = 'b'
const
=
'foo'
;
// a = 'f'; b = 'o'
10.10.4 Valori di ritorno multipli #
Per vedere l’utilità di valori di ritorno multipli, implementiamo una funzione findElement(a, p)
che cerca il primo elemento nell’Array a
per il quale la funzione p
restituisce true
. La domanda è: cosa dovrebbe restituire findElement()
? A volte uno è interessato all’elemento stesso, a volte nel suo indice, a volte in entrambi. La seguente implementazione restituisce entrambi.
function
findElement
(
array
,
predicate
)
{
for
(
const
of
array
.
entries
())
{
// (A)
if
(
predicate
(
element
,
index
,
array
))
{
// We found an element:
return
{
element
,
index
};
// Same as (property value shorthands):
// { element: element, index: index }
}
}
// We couldn't find anything; return failure values:
return
{
element
:
undefined
,
index
:
-
1
};
}
La funzione itera su tutti gli elementi di array
, tramite il metodo Array entries()
, che restituisce un iterabile su coppie (riga A). Le parti delle coppie sono accessibili tramite destrutturazione.
Usiamo findElement()
:
const
arr
=
;
const
{
element
,
index
}
=
findElement
(
arr
,
x
=>
x
%
2
===
0
);
// element = 8, index = 1
Diverse funzionalità di ECMAScript 6 ci hanno permesso di scrivere codice più conciso: Il callback è una funzione a freccia; il valore restituito viene destrutturato tramite un modello di oggetto con stenografie di valore di proprietà.
A causa di index
e element
che si riferiscono anche alle chiavi di proprietà, l’ordine in cui le menzioniamo non ha importanza. Possiamo scambiarli e non cambia nulla:
const
{
index
,
element
}
=
findElement
(
···
);
Abbiamo gestito con successo il caso di aver bisogno sia di index che di element. Cosa succede se siamo interessati solo a uno di loro? Si scopre che, grazie a ECMAScript 6, la nostra implementazione può occuparsi anche di questo. E il sovraccarico sintattico rispetto alle funzioni con singoli valori di ritorno è minimo.
const
a
=
;
const
{
element
}
=
findElement
(
a
,
x
=>
x
%
2
===
0
);
// element = 8
const
{
index
}
=
findElement
(
a
,
x
=>
x
%
2
===
0
);
// index = 1
Ogni volta, estraiamo solo il valore dell’unica proprietà di cui abbiamo bisogno.
10.11 L’algoritmo di destrutturazione #
Questa sezione esamina la destrutturazione da una diversa angolazione: come algoritmo di pattern matching ricorsivo.
Alla fine, userò l’algoritmo per spiegare la differenza tra le seguenti due dichiarazioni di funzione.
function
move
({
x
=
0
,
y
=
0
}
=
{})
{
···
}
function
move
({
x
,
y
}
=
{
x
:
0
,
y
:
0
})
{
···
}
10.11.1 L’algoritmo #
Un’assegnazione di destrutturazione è simile a questa:
"
pattern
"
=
"
value
"
Vogliamo usare pattern
per estrarre i dati da value
. Descriverò ora un algoritmo per farlo, che è noto nella programmazione funzionale come pattern matching (short: matching). L’algoritmo specifica l’operatore ←
(“match against”) per l’assegnazione di destrutturazione che corrisponde a pattern
contro a value
e assegna alle variabili mentre lo fa:
"
pattern
"
←
"
value
"
L’algoritmo viene specificato tramite regole ricorsive che smontano entrambi gli operandi dell’operatore ←
. La notazione dichiarativa potrebbe richiedere un po ‘ di tempo per abituarsi, ma rende la specifica dell’algoritmo più concisa. Ogni regola ha due parti:
- La testa (prima riga) descrive la condizione che attiva la regola.
- Il corpo (linee rimanenti) descrive cosa succede se la regola viene attivata.
Diamo un’occhiata ad un esempio:
- (2c)
{key: "pattern", "properties"} ← obj
"
pattern
"
←
obj
.
key
{
"
properties
"
}
←
obj
- (2e)
{} ← obj
(nessuna proprietà di sinistra)
// Nothing to do
In regola (2c), la testa significa che questa regola viene eseguita se c’è un oggetto modello con almeno una proprietà e zero o più proprietà rimanenti. Questo modello è abbinato a un valore obj
. L’effetto di questa regola è che l’esecuzione continua con il modello di valore della proprietà che viene confrontato con obj.key
e le proprietà rimanenti con obj
.
Nella regola (2e), l’head significa che questa regola viene eseguita se il modello di oggetto vuoto {}
è abbinato a un valore obj
. Allora non c’è niente da fare.
Ogni volta che viene richiamato l’algoritmo, le regole vengono controllate dall’alto verso il basso e viene eseguita solo la prima regola applicabile.
Mostro solo l’algoritmo per l’assegnazione di destrutturazione. Destrutturazione dichiarazioni variabili e destrutturazione definizioni dei parametri funzionano allo stesso modo.
Non copro le funzionalità avanzate (chiavi di proprietà calcolate; abbreviazioni del valore della proprietà; proprietà dell’oggetto e gli elementi dell’array come obiettivi di assegnazione), sia. Solo le basi.
10.11.1.1 Patterns #
Un pattern è:
- Una variabile:
x
- Un modello di oggetto:
{"properties"}
- Un modello di matrice:
Ciascuna delle sezioni seguenti descrive uno di questi tre casi.
Le tre sezioni seguenti specificano come gestire questi tre casi. Ogni sezione contiene una o più regole numerate.
10.11.1.2 Variabile #
- (1)
x ← value
(compresoundefined
enull
)
x
=
value
10.11.1.3 Oggetto modello #
- (2a)
{"properties"} ← undefined
throw
new
TypeError
();
- (2b)
{"properties"} ← null
throw
new
TypeError
();
- (2c)
{key: "pattern", "properties"} ← obj
"
pattern
"
←
obj
.
key
{
"
properties
"
}
←
obj
- (2d)
{key: "pattern" = default_value, "properties"} ← obj
const
tmp
=
obj
.
key
;
if
(
tmp
!==
undefined
)
{
"
pattern
"
←
tmp
}
else
{
"
pattern
"
←
default_value
}
{
"
properties
"
}
←
obj
- (2e)
{} ← obj
(nessuna proprietà di sinistra)
// Nothing to do
10.11.1.4 Matrice #
Array modello e iterable. L’algoritmo per la Matrice di destrutturazione inizia con una Matrice e un iterable:
- (3a)
← non_iterable
assert(!isIterable(non_iterable))
throw
new
TypeError
();
- (3b)
← iterable
assert(isIterable(iterable))
const
iterator
=
iterable
();
"
elements
"
←
iterator
funzione di supporto:
function
isIterable
(
value
)
{
return
(
value
!==
null
&&
typeof
value
===
'object'
&&
typeof
value
===
'function'
);
}
gli elementi dell’Array e iteratore. L’algoritmo continua con gli elementi del modello (lato sinistro della freccia) e l’iteratore che è stato ottenuto dall’iterabile (lato destro della freccia).
- (3c)
"pattern", "elements" ← iterator
"
pattern
"
←
getNext
(
iterator
)
// undefined after last item
"
elements
"
←
iterator
- (3d)
"pattern" = default_value, "elements" ← iterator
const
tmp
=
getNext
(
iterator
);
// undefined after last item
if
(
tmp
!==
undefined
)
{
"
pattern
"
←
tmp
}
else
{
"
pattern
"
←
default_value
}
"
elements
"
←
iterator
- (3e)
, "elements" ← iterator
(foro, elisione)
getNext
(
iterator
);
// skip
"
elements
"
←
iterator
- (3f)
..."pattern" ← iterator
(sempre ultima parte!)
const
tmp
=
;
for
(
const
elem
of
iterator
)
{
tmp
.
push
(
elem
);
}
"
pattern
"
←
tmp
- (3g)
← iterator
(senza elementi di sinistra)
// Nothing to do
funzione di supporto:
function
getNext
(
iterator
)
{
const
{
done
,
value
}
=
iterator
.
next
();
return
(
done
?
undefined
:
value
);
}
10.11.2 Applicando l’algoritmo #
In ECMAScript 6, è possibile simulare i parametri con nome se il chiamante utilizza un oggetto letterale e il chiamato utilizza destrutturazione. Questa simulazione è spiegata in dettaglio nel capitolo sulla gestione dei parametri. Il seguente codice mostra un esempio: la funzione move1()
ha due parametri denominati, x
e y
:
function
move1
({
x
=
0
,
y
=
0
}
=
{})
{
// (A)
return
;
}
move1
({
x
:
3
,
y
:
8
});
//
move1
({
x
:
3
});
//
move1
({});
//
move1
();
//
Ci sono tre valori predefiniti nella riga A:
- I primi due valori predefiniti consentono di omettere
x
ey
. - Il terzo valore predefinito consente di chiamare
move1()
senza parametri (come nell’ultima riga).
Ma perché definire i parametri come nel frammento di codice precedente? Perché non come segue-che è anche il codice ES6 completamente legale?
function
move2
({
x
,
y
}
=
{
x
:
0
,
y
:
0
})
{
return
;
}
Per capire perché move1()
è corretto, usiamo entrambe le funzioni per due esempi. Prima di farlo, vediamo come il passaggio dei parametri può essere spiegato tramite la corrispondenza.
10.11.2.1 Background: passando i parametri tramite matching #
Per le chiamate di funzione, i parametri formali (all’interno delle definizioni delle funzioni) vengono confrontati con i parametri effettivi (all’interno delle chiamate di funzione). Ad esempio, prendere la seguente definizione di funzione e la seguente chiamata di funzione.
function
func
(
a
=
0
,
b
=
0
)
{
···
}
func
(
1
,
2
);
I parametri a
e b
sono impostati in modo simile alla seguente destrutturazione.
←
10.11.2.2 Usando move2()
#
Esaminiamo come funziona la destrutturazione per move2()
.
Esempio 1. move2()
porta a questa destrutturazione:
←
L’elemento del singolo Array sul lato sinistro non ha una corrispondenza sul lato destro, motivo per cui {x,y}
è abbinato al valore predefinito e non ai dati dal lato destro (regole 3b, 3d):
{
x
,
y
}
←
{
x
:
0
,
y
:
0
}
La parte sinistra contiene il valore della proprietà scorciatoie, è un’abbreviazione per la:
{
x
:
x
,
y
:
y
}
←
{
x
:
0
,
y
:
0
}
Questa destrutturazione conduce alle due seguenti incarichi (regole 2c, 1):
x
=
0
;
y
=
0
;
Esempio 2. Esaminiamo la chiamata di funzione move2({z:3})
che porta alla seguente destrutturazione:
←
C’è un elemento di matrice all’indice 0 sul lato destro. Pertanto, il valore predefinito viene ignorato e il passo successivo è (regola 3d):
{
x
,
y
}
←
{
z
:
3
}
Ciò porta a impostare sia x
che y
su undefined
, che non è ciò che vogliamo.
10.11.2.3 Utilizzo move1()
#
Proviamo move1()
.
Esempio 1: move1()
←
non Abbiamo un elemento di un Array con indice 0 sul lato destro e utilizzare il valore predefinito (regola 3d):
{
x
=
0
,
y
=
0
}
←
{}
La parte sinistra contiene il valore della proprietà scorciatoie, il che significa che questa destrutturazione è equivalente a:
{
x
:
x
=
0
,
y
:
y
=
0
}
←
{}
Né la proprietà x
né la proprietà y
hanno una corrispondenza sul lato destro. Pertanto, vengono utilizzati i valori predefiniti e seguenti destructurings vengono eseguite successivo (regola 2d):
x
←
0
y
←
0
Che conduce alle seguenti assegnazioni (regola 1):
x
=
0
y
=
0
Esempio 2: move1({z:3})
←
Il primo elemento della Matrice è una partita sulla destra e quella partita è utilizzato per continuare la destrutturazione (regola 3d):
{
x
=
0
,
y
=
0
}
←
{
z
:
3
}
Come nell’esempio 1, non ci sono immobili x
e y
sul lato destro e vengono utilizzati i valori predefiniti:
x
=
0
y
=
0
10.11.2.4 Conclusione #
Gli esempi dimostrano che i valori di default sono una funzionalità di parti del modello (oggetto di proprietà o di elementi di un Array). Se una parte non ha corrispondenza o è confrontata con undefined
, viene utilizzato il valore predefinito. Cioè, il modello è abbinato al valore predefinito, invece.