10. Destrukcja
10. Destrukcja #
- 10.1. Przegląd
- 10.1.1. Niszczenie obiektów
- 10.1.2. Destrukcja tablicy
- 10.1.3. Gdzie można użyć destrukcji?
- 10.2. Tło: konstruowanie danych a wyodrębnianie danych
- 10.3. Wzorce do destrukcji
- 10.3.1. Wybierz to, czego potrzebujesz
- 10.4. Jak wzorce mają dostęp do wnętrzności wartości?
- 10.4.1. Wzorce obiektów wymuszają wartości dla obiektów
- 10.4.2. Wzorce tablic działają z iterablami
- 10.5. Wartości domyślne
- 10.5.1.
undefined
wyzwala domyślne wartości - 10.5.2. Wartości domyślne są obliczane na żądanie
- 10.5.3. Wartości domyślne mogą odnosić się do innych zmiennych we wzorze
- 10.5.4. Domyślne wartości dla wzorców
- 10.5.5. Bardziej złożone wartości domyślne
- 10.5.1.
- 10.6. Więcej funkcji niszczenia obiektów
- 10.6.1. Skróty wartości nieruchomości
- 10.6.2. Computed Property keys
- 10.7. Więcej funkcji destrukcji tablicy
- 10.7.1. Elision
- 10.7.2. Operator Rest (
...
)
- 10.8. Możesz przypisać więcej niż tylko zmienne
- 10.9. Pułapki destrukcji
- 10.9.1. Nie zaczynaj wypowiedzi od klamry
- 10.10. Przykłady destrukcji
- 10.10.1. Destrukcja zwróconych tablic
- 10.10.2. Niszczenie zwróconych obiektów
- 10.10.3. Tablica-destrukcja iterowalnych wartości
- 10.10.4. Wiele wartości zwracanych
- 10.11. Algorytm destrukcji
- 10.11.1. Algorytm
- 10.11.2. Zastosowanie algorytmu
10.1 przegląd #
destrukcja jest wygodnym sposobem wyodrębniania wielu wartości z danych przechowywanych w (prawdopodobnie zagnieżdżonych) obiektach i tablicach. Może być używany w miejscach, które otrzymują dane (np. po lewej stronie przypisania). Sposób wyodrębniania wartości jest określony za pomocą wzorców (Czytaj dalej, aby zobaczyć przykłady).
10.1.1 niszczenie obiektów #
niszczenie obiektów:
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'
destrukcja pomaga w przetwarzaniu wartości zwrotnych:
const
obj
=
{
foo
:
123
};
const
{
writable
,
configurable
}
=
Object
.
getOwnPropertyDescriptor
(
obj
,
'foo'
);
console
.
log
(
writable
,
configurable
);
// true true
10.1.2 destrukcja tablicy #
destrukcja tablicy (działa dla wszystkich iteracyjnych wartości):
const
iterable
=
;
const
=
iterable
;
// x = 'a'; y = 'b'
destrukcja pomaga w przetwarzaniu wartości zwrotnych:
const
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
'2999-12-31'
);
10.1.3 gdzie można użyć destrukcji? #
destrukcji można użyć w następujących miejscach (pokazuję wzorce tablic do zademonstrowania; wzorce obiektów działają równie dobrze):
// Variable declarations:
const
=
;
let
=
;
var
=
;
// Assignments:
=
;
// Parameter definitions:
function
f
()
{
···
}
f
();
można również zniszczyć w pętli for-of
:
const
arr
=
;
for
(
const
of
arr
.
entries
())
{
console
.
log
(
index
,
element
);
}
// Output:
// 0 a
// 1 b
10.2 Tło: konstruowanie danych a wyodrębnianie danych #
aby w pełni zrozumieć, czym jest destrukcja, zbadajmy najpierw jego szerszy kontekst.
JavaScript ma operacje na konstruowaniu danych, jedna właściwość na raz:
const
obj
=
{};
obj
.
first
=
'Jane'
;
obj
.
last
=
'Doe'
;
ta sama składnia może być użyta do wyodrębnienia danych. Ponownie, jedna nieruchomość na raz:
const
f
=
obj
.
first
;
const
l
=
obj
.
last
;
dodatkowo, istnieje składnia do konstruowania wielu właściwości w tym samym czasie, za pomocą dosłownego obiektu:
const
obj
=
{
first
:
'Jane'
,
last
:
'Doe'
};
przed ES6 nie istniał odpowiedni mechanizm ekstrakcji danych. Tym właśnie jest destrukcja-pozwala wyodrębnić wiele właściwości z obiektu za pomocą wzorca obiektu. Na przykład po lewej stronie zadania:
const
{
first
:
f
,
last
:
l
}
=
obj
;
można również niszczyć Tablice za pomocą wzorców:
const
=
;
// x = 'a'; y = 'b'
10.3 wzory destrukcji #
w destrukcji biorą udział następujące dwie strony:
- źródło destrukcji: dane, które mają zostać zniszczone. Na przykład po prawej stronie zadania destrukcyjnego.
- destrukcja celu: wzór używany do destrukcji. Na przykład po lewej stronie zadania destrukcyjnego.
celem destrukcji jest jeden z trzech wzorców:
- cel zadania. Na przykład:
x
- celem przypisania jest zwykle zmienna. Ale w zadaniu destrukcji masz więcej opcji, jak wyjaśnię później.
- wzór obiektu. Na przykład:
{ first: "pattern", last: "pattern" }
- części wzorca obiektu są właściwościami, wartości właściwości są ponownie wzorcami (rekurencyjnie).
- wzór tablicy. Na przykład:
- części wzorca tablicy są elementami, elementy są ponownie wzorcami (rekurencyjnie).
oznacza to, że można zagnieżdżać wzory, dowolnie głęboko:
const
obj
=
{
a
:
,
b
:
true
};
const
{
a
:
}
=
obj
;
// f = 123
10.3.1 Wybierz to, czego potrzebujesz #
jeśli niszczysz obiekt, wymieniasz tylko te właściwości, które Cię interesują:
const
{
x
:
x
}
=
{
x
:
7
,
y
:
3
};
// x = 7
jeśli zniszczysz tablicę, możesz wyodrębnić tylko prefiks:
const
=
;
// x='a'; y='b';
10.4 jak wzorce mają dostęp do wnętrzności wartości? #
w przypisaniu pattern = someValue
, jak pattern
ma dostęp do tego, co znajduje się w środku someValue
?
10.4.1 wzorce obiektów wymuszają wartości do obiektów #
wzorce obiektów wymuszają destrukcję źródeł do obiektów przed uzyskaniem dostępu do właściwości. Oznacza to, że działa z prymitywnymi wartościami:
const
{
length
:
len
}
=
'abc'
;
// len = 3
const
{
toString
:
s
}
=
123
;
// s = Number.prototype.toString
10.4.1.1 brak obiektu-destrukcja wartości #
wymuszenie na obiekcie nie jest wykonywane poprzez Object()
, lecz poprzez wewnętrzną operację ToObject()
. Obie operacje obsługują undefined
i null
inaczej.
Object()
konwertuje pierwotne wartości na obiekty opakowujące i pozostawia obiekty nietknięte:
> 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
w konsekwencji można użyć wzorca pustego obiektu {}
, aby sprawdzić, czy wartość jest wymuszalna dla obiektu. Jak widzieliśmy, tylko undefined
i null
nie są:
({}
=
);
// OK, Arrays are coercible to objects
({}
=
'abc'
);
// OK, strings are coercible to objects
({}
=
undefined
);
// TypeError
({}
=
null
);
// TypeError
nawiasy wokół wyrażeń są konieczne, ponieważ instrukcje nie mogą zaczynać się od nawiasów klamrowych w JavaScript (szczegóły wyjaśniono później).
10.4.2 wzorce tablic działają z iterablami #
destrukcja tablicy używa iteratora, aby dostać się do elementów źródła. Dlatego możesz zniszczyć dowolną wartość, która jest iterowalna. Spójrzmy na przykłady wartości iteracyjnych.
ciągi są iterowalne:
const
=
'abc'
;
// x='a'; y=
nie zapominaj, że iterator nad łańcuchami zwraca punkty kodu („znaki Unicode”, 21 bitów), a nie jednostki kodu („znaki JavaScript”, 16 bitów). (Aby uzyskać więcej informacji na temat Unicode, zapoznaj się z rozdziałem ” Rozdział 24. Unicode i JavaScript ” w „Speaking JavaScript”.) Na przykład:
const
=
'a\uD83D\uDCA9c'
;
// x='a'; y='\uD83D\uDCA9'; z='c'
nie można uzyskać dostępu do elementów zestawu za pomocą indeksów, ale można to zrobić za pomocą iteratora. Dlatego destrukcja tablic działa dla zestawów:
const
=
new
Set
();
// x='a'; y='b';
iterator Set
zawsze zwraca elementy w kolejności, w jakiej zostały wstawione, dlatego wynik poprzedniego destrukcji jest zawsze taki sam.
10.4.2.1 brak destrukcji tablicy wartość #
wartość jest iterowalna, jeśli posiada metodę, której kluczem jest Symbol.iterator
, która zwraca obiekt. Array-destructing wyrzuca TypeError
, jeśli wartość do zniszczenia nie jest iteracyjna:
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
TypeError
jest wyrzucany jeszcze przed dostępem do elementów iterowalnych, co oznacza, że możesz użyć pustego wzorca tablicy , aby sprawdzić, czy wartość jest iterowalna:
=
{};
// TypeError, empty objects are not iterable
=
undefined
;
// TypeError, not iterable
=
null
;
// TypeError, not iterable
10.5 wartości domyślne #
wartości domyślne są opcjonalną funkcją wzorców. Stanowią one rezerwę, jeśli nic nie zostanie znalezione w źródle. Jeśli część (właściwość obiektu lub element tablicy) nie ma dopasowania w źródle, jest dopasowywana do:
- jego wartość domyślna (jeśli podano; jest opcjonalny)
-
undefined
(inaczej)
spójrzmy na przykład. W poniższej destrukcji element o indeksie 0 nie ma dopasowania po prawej stronie. Dlatego destrukcja jest kontynuowana przez dopasowanie x
do 3, co prowadzi do Ustawienia x
na 3.
const
=
;
// x = 3; y = undefined
można również używać wartości domyślnych we wzorcach obiektów:
const
{
foo
:
x
=
3
,
bar
:
y
}
=
{};
// x = 3; y = undefined
10.5.1 undefined
wyzwalacze domyślne wartości #
domyślne wartości są również używane, jeśli część ma dopasowanie i to dopasowanie jest undefined
:
const
=
;
// x = 1
const
{
prop
:
y
=
2
}
=
{
prop
:
undefined
};
// y = 2
uzasadnienie tego zachowania jest wyjaśnione w następnym rozdziale, w sekcji o wartościach domyślnych parametrów.
10.5.2 wartości domyślne są obliczane na żądanie #
same wartości domyślne są obliczane tylko wtedy, gdy są potrzebne. Innymi słowy, owa destrukcja:
const
{
prop
:
y
=
someFunc
()}
=
someValue
;
jest równoważne:
let
y
;
if
(
someValue
.
prop
===
undefined
)
{
y
=
someFunc
();
}
else
{
y
=
someValue
.
prop
;
}
można zauważyć, że jeśli używasz 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
liczy się jednak kolejność: zmienne x
i y
są deklarowane od lewej do prawej i tworzą ReferenceError
, jeśli są dostępne przed ich deklaracjami:
const
=
;
// ReferenceError
10.5.4 domyślne wartości dla wzorców #
do tej pory widzieliśmy tylko domyślne wartości dla zmiennych, ale można je również skojarzyć z wzorcami:
const
=
;
Co to znaczy? Przypomnij regułę dla wartości domyślnych: jeśli część nie ma dopasowania w źródle, destrukcja jest kontynuowana z wartością domyślną.
element o indeksie 0 nie ma dopasowania, dlatego destrukcja trwa nadal z:
const
{
prop
:
x
}
=
{};
// x = undefined
możesz łatwiej zobaczyć, dlaczego wszystko działa w ten sposób, jeśli zastąpisz wzorzec { prop: x }
zmienną pattern
:
const
=
;
10.5.5 bardziej złożone wartości domyślne #
przyjrzyjmy się dalej wartościom domyślnym wzorców. W poniższym przykładzie przypisujemy wartość x
poprzez wartość domyślną { prop: 123 }
:
const
=
;
ponieważ element tablicy o indeksie 0 nie ma dopasowania po prawej stronie, destrukcja przebiega następująco i x
jest ustawiona na 123.
const
{
prop
:
x
}
=
{
prop
:
123
};
// x = 123
jednak x
nie jest przypisana w ten sposób wartość, jeśli po prawej stronie znajduje się element o indeksie 0, ponieważ wtedy wartość domyślna nie jest wyzwalana.
const
=
;
w tym przypadku destrukcja jest kontynuowana z:
const
{
prop
:
x
}
=
{};
// x = undefined
Tak więc, jeśli chcesz, aby x
miał wartość 123, jeśli brakuje obiektu lub właściwości, musisz określić domyślną wartość dla samej wartości x
:
const
=
;
tutaj destrukcja przebiega następująco, niezależnie od tego, czy prawa strona jest czy
.
const
{
prop
:
x
=
123
}
=
{};
// x = 123
10.6 więcej funkcji destrukcji obiektów #
10.6.1 skróty wartości właściwości #
skróty wartości właściwości są cechą literałów obiektów: Jeśli wartość właściwości jest zmienną o tej samej nazwie co klucz właściwości, to można pominąć klucz. Działa to również na destrukcję:
const
{
x
,
y
}
=
{
x
:
11
,
y
:
8
};
// x = 11; y = 8
// Same as:
const
{
x
:
x
,
y
:
y
}
=
{
x
:
11
,
y
:
8
};
można również łączyć skróty wartości właściwości z wartościami domyślnymi:
const
{
x
,
y
=
1
}
=
{};
// x = undefined; y = 1
10.6.2 Computed property keys #
Computed property keys to kolejna literalna funkcja obiektu, która działa również przy destrukcji. Klucz właściwości można określić za pomocą wyrażenia, jeśli umieścimy go w nawiasach kwadratowych:
const
FOO
=
'foo'
;
const
{
:
f
}
=
{
foo
:
123
};
// f = 123
Computed property keys pozwalają niszczyć właściwości, których klucze są symbolami:
// 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 więcej funkcji destrukcji tablicy #
10.7.1 Elision #
Elision pozwala używać składni „dziur” tablicy do pomijania elementów podczas destrukcji:
const
=
;
// x = 'c'; y = 'd'
10.7.2 Operator Rest (...
) #
operator rest pozwala wyodrębnić pozostałe elementy iteracyjne do tablicy. Jeśli ten operator jest używany wewnątrz wzorca tablicy, musi być ostatni:
const
=
;
// x='a'; y=
jeśli operator nie może znaleźć żadnych elementów, dopasowuje swój argument do pustej tablicy. Oznacza to, że nigdy nie produkuje undefined
lub null
. Na przykład:
const
=
;
// x='a'; y=undefined; z=
operand operatora rest nie musi być zmienną, można też użyć wzorców:
const
]
=
;
// x = 'a'; y = 'b'; z = 'c'
Operator rest uruchamia następujące destrukcje:
=
10.8 możesz przypisać więcej niż tylko zmienne #
jeśli przypisujesz poprzez destrukcję, każdy cel przypisania może być wszystkim, co jest dozwolone po lewej stronie normalnego przypisania.
na przykład odwołanie do właściwości (obj.prop
):
const
obj
=
{};
({
foo
:
obj
.
prop
}
=
{
foo
:
123
});
console
.
log
(
obj
);
// {prop:123}
lub odniesienie do elementu tablicy(arr
):
const
arr
=
;
({
bar
:
arr
}
=
{
bar
:
true
});
console
.
log
(
arr
);
//
można również przypisać do Właściwości obiektu i elementów tablicy za pomocą operatora rest (...
):
const
obj
=
{};
=
;
// first = 'a'; obj.prop =
jeśli deklarujesz zmienne lub definiujesz parametry poprzez destrukcję, musisz użyć prostych identyfikatorów, nie możesz odwoływać się do Właściwości obiektu i elementów tablicy.
10.9 pułapki destrukcji #
przy użyciu destrukcji należy pamiętać o dwóch rzeczach:
- nie możesz zacząć zeznań od klamry.
- podczas destrukcji możesz zadeklarować zmienne lub przypisać do nich, ale nie obie.
kolejne dwie sekcje zawierają szczegóły.
10.9.1 nie rozpoczynaj instrukcji nawiasem klamrowym #
ponieważ bloki kodu zaczynają się nawiasem klamrowym, polecenia nie mogą zaczynać się od jednego. Jest to niefortunne w przypadku korzystania z destrukcji obiektów w przypisaniu:
{
a
,
b
}
=
someObject
;
// SyntaxError
obejście polega na umieszczeniu pełnego wyrażenia w nawiasach:
({
a
,
b
}
=
someObject
);
// OK
nie działa następująca składnia:
({
a
,
b
})
=
someObject
;
// SyntaxError
z let
, var
i const
kręcone szelki nigdy nie powodują problemów:
const
{
a
,
b
}
=
someObject
;
// OK
10.10 przykładów destrukcji #
Zacznijmy od kilku mniejszych przykładów.
pętla for-of
obsługuje destrukcję:
const
map
=
new
Map
().
set
(
false
,
'no'
).
set
(
true
,
'yes'
);
for
(
const
of
map
)
{
console
.
log
(
key
+
' is '
+
value
);
}
możesz użyć destrukcji do zamiany wartości. To jest coś, co silniki mogą zoptymalizować, tak, że nie zostanie utworzona tablica.
=
;
możesz użyć destrukcji, aby podzielić tablicę:
const
=
;
// first = 'a'; rest =
10.10.1 destrukcja zwróconych tablic #
niektóre wbudowane operacje JavaScript zwracają Tablice. Destrukcja pomaga w ich przetwarzaniu:
const
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
'2999-12-31'
);
jeśli jesteś zainteresowany tylko grupami (a nie kompletnym dopasowaniem, all
), możesz użyć elision, aby pominąć element tablicy w indeksie 0:
const
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
'2999-12-31'
);
exec()
zwraca null
, jeśli wyrażenie regularne nie jest zgodne. Niestety, nie możesz obsłużyć null
za pomocą wartości domyślnych, dlatego w tym przypadku musisz użyć operatora Or (||
) :
const
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
someStr
)
||
;
Array.prototype.split()
zwraca tablicę. Dlatego destrukcja jest przydatna, jeśli interesują Cię elementy, a nie tablica:
const
cells
=
'Jane\tDoe\tCTO'
const
=
cells
.
split
(
'\t'
);
console
.
log
(
firstName
,
lastName
,
title
);
10.10.2 destrukcja zwracanych obiektów #
destrukcja jest również przydatna do wyciągania danych z obiektów, które są zwracane przez funkcje lub metody. Na przykład metoda iteratora next()
zwraca obiekt o dwóch właściwościach, done
i value
. Poniższy kod rejestruje wszystkie elementy tablicy arr
poprzez iterator iter
. W linii A stosuje się destrukcję.
const
arr
=
;
const
iter
=
arr
();
while
(
true
)
{
const
{
done
,
value
}
=
iter
.
next
();
// (A)
if
(
done
)
break
;
console
.
log
(
value
);
}
10.10.3 array-destructing wartości iteratywne #
array-destructing działa z dowolną wartością iteratywną. To jest czasami przydatne:
const
=
new
Set
().
add
(
'a'
).
add
(
'b'
);
// x = 'a'; y = 'b'
const
=
'foo'
;
// a = 'f'; b = 'o'
10.10.4 wiele zwracanych wartości #
aby zobaczyć użyteczność wielu zwracanych wartości, zaimplementujmy funkcję findElement(a, p)
, która wyszukuje pierwszy element w tablicy a
, dla którego funkcja p
zwraca true
. Pytanie brzmi: co należy zwrócić findElement()
? Czasem interesuje nas sam element, czasem jego indeks, czasem jedno i drugie. Następująca implementacja zwraca oba.
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
};
}
funkcja iteruje nad wszystkimi elementami array
, za pomocą metody Array entries()
, która zwraca iterowalną nad parami (linia A). Części par są dostępne poprzez destrukcję.
użyjmy findElement()
:
const
arr
=
;
const
{
element
,
index
}
=
findElement
(
arr
,
x
=>
x
%
2
===
0
);
// element = 8, index = 1
kilka funkcji ECMAScript 6 pozwoliło nam napisać bardziej zwięzły kod: wywołanie zwrotne jest funkcją strzałki; wartość zwracana jest niszczona za pomocą wzorca obiektu ze skróconymi wartościami właściwości.
ze względu na index
i element
również odnoszące się do kluczy właściwości, kolejność, w jakiej je wspominamy, nie ma znaczenia. Możemy je zamienić i nic się nie zmienia:
const
{
index
,
element
}
=
findElement
(
···
);
z powodzeniem obsłużyliśmy przypadek konieczności zarówno indeksu, jak i elementu. Co jeśli interesuje nas tylko jeden z nich? Okazuje się, że dzięki ECMAScript 6 nasza implementacja może się tym zająć. A narzut składniowy w porównaniu z funkcjami z pojedynczymi wartościami zwracanymi jest minimalny.
const
a
=
;
const
{
element
}
=
findElement
(
a
,
x
=>
x
%
2
===
0
);
// element = 8
const
{
index
}
=
findElement
(
a
,
x
=>
x
%
2
===
0
);
// index = 1
za każdym razem wyodrębniamy tylko wartość jednej właściwości, której potrzebujemy.
10.11 algorytm destrukcji #
Ta sekcja patrzy na destrukcję pod innym kątem: jako rekurencyjny algorytm dopasowywania wzorców.
na końcu użyję algorytmu, aby wyjaśnić różnicę między następującymi dwiema deklaracjami funkcji.
function
move
({
x
=
0
,
y
=
0
}
=
{})
{
···
}
function
move
({
x
,
y
}
=
{
x
:
0
,
y
:
0
})
{
···
}
10.11.1 algorytm #
zadanie destrukcyjne wygląda tak:
"
pattern
"
=
"
value
"
chcemy użyć pattern
, aby wyodrębnić dane z value
. Opiszę teraz algorytm, który jest znany w programowaniu funkcyjnym jako pattern matching (w skrócie: dopasowanie). Algorytm określa operatora ←
(„match against”) dla destrukcyjnego przypisania, który dopasowuje pattern
do value
i przyporządkowuje zmienne podczas tego procesu:
"
pattern
"
←
"
value
"
algorytm jest określony za pomocą reguł rekurencyjnych, które rozdzielają oba operandy operatora ←
. Notacja deklaratywna może zająć trochę czasu, ale sprawia, że specyfikacja algorytmu jest bardziej zwięzła. Każda reguła składa się z dwóch części:
- head (pierwsza linia) opisuje warunek, który wyzwala regułę.
- ciało (pozostałe linie) opisuje, co się stanie, jeśli reguła zostanie wywołana.
spójrzmy na przykład:
- (2c)
{key: "pattern", "properties"} ← obj
"
pattern
"
←
obj
.
key
{
"
properties
"
}
←
obj
- (2e)
{} ← obj
(brak obiektów)
// Nothing to do
w rule (2C), head oznacza, że ta reguła jest wykonywana, jeśli istnieje wzorzec obiektu z co najmniej jedną właściwością i zero lub więcej pozostałych właściwości. Ten wzorzec jest dopasowywany do wartości obj
. Efekt tej reguły jest taki, że wykonanie jest kontynuowane przy dopasowaniu wzorca wartości właściwości do obj.key
, a pozostałych właściwości do obj
.
w rule (2e), head oznacza, że ta reguła jest wykonywana, jeśli pusty wzorzec obiektu {}
jest dopasowany do wartości obj
. Więc nic nie można zrobić.
za każdym razem, gdy algorytm jest wywoływany, reguły są sprawdzane od góry do dołu i wykonywana jest tylko pierwsza reguła, która ma zastosowanie.
pokazuję tylko algorytm destrukcji. Podobnie działają deklaracje zmiennych destrukcyjnych i definicje parametrów destrukcyjnych.
nie zajmuję się zaawansowanymi funkcjami (computed property keys; property value shorthands; właściwości obiektu i elementy tablicy jako cele przypisania). Tylko podstawy.
10.11.1.1 wzory #
wzór jest albo:
- zmienna:
x
- wzór obiektu:
{"properties"}
- wzór tablicy:
każda z poniższych sekcji opisuje jeden z tych trzech przypadków.
poniższe trzy sekcje określają sposób postępowania z tymi trzema przypadkami. Każda sekcja zawiera jedną lub więcej ponumerowanych reguł.
10.11.1.2 zmienne #
- (1)
x ← value
(w tymundefined
inull
)
x
=
value
10.11.1.3 wzór obiektu #
- (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
(brak obiektów)
// Nothing to do
10.11.1.4 wzór tablicy #
wzór tablicy i iteracyjny. Algorytm destrukcji tablicy zaczyna się od wzorca tablicy i iteracyjnego:
- (3a)
← non_iterable
assert(!isIterable(non_iterable))
throw
new
TypeError
();
- (3b)
← iterable
assert(isIterable(iterable))
const
iterator
=
iterable
();
"
elements
"
←
iterator
funkcja pomocnicza:
function
isIterable
(
value
)
{
return
(
value
!==
null
&&
typeof
value
===
'object'
&&
typeof
value
===
'function'
);
}
elementy tablicy i iterator. Algorytm kontynuuje elementy wzorca (po lewej stronie Strzałki) i iteratora, który został uzyskany z iterable (po prawej stronie strzałki).
- (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
(hole, elision)
getNext
(
iterator
);
// skip
"
elements
"
←
iterator
- (3f)
..."pattern" ← iterator
(zawsze ostatnia część!)
const
tmp
=
;
for
(
const
elem
of
iterator
)
{
tmp
.
push
(
elem
);
}
"
pattern
"
←
tmp
- (3g)
← iterator
(brak elementów)
// Nothing to do
funkcja pomocnicza:
function
getNext
(
iterator
)
{
const
{
done
,
value
}
=
iterator
.
next
();
return
(
done
?
undefined
:
value
);
}
10.11.2 stosując algorytm #
w ECMAScript 6, można symulować nazwane parametry, jeśli wywołujący używa dosłownego obiektu, a wywołujący używa destrukcji. Ta symulacja została szczegółowo wyjaśniona w rozdziale dotyczącym obsługi parametrów. Poniższy kod pokazuje przykład: funkcja move1()
ma dwa nazwane parametry, x
i y
:
function
move1
({
x
=
0
,
y
=
0
}
=
{})
{
// (A)
return
;
}
move1
({
x
:
3
,
y
:
8
});
//
move1
({
x
:
3
});
//
move1
({});
//
move1
();
//
w wierszu A są trzy wartości domyślne:
- pierwsze dwie wartości domyślne pozwalają pominąć
x
iy
. - trzecia wartość domyślna pozwala na wywołanie
move1()
bez parametrów (jak w ostatniej linii).
ale dlaczego mielibyście zdefiniować parametry jak w poprzednim fragmencie kodu? Dlaczego nie w następujący sposób-który jest również całkowicie legalny kod ES6?
function
move2
({
x
,
y
}
=
{
x
:
0
,
y
:
0
})
{
return
;
}
aby zobaczyć, dlaczego move1()
jest poprawne, użyjmy obu funkcji dla dwóch przykładów. Zanim to zrobimy, zobaczmy, jak przekazywanie parametrów może być wyjaśnione poprzez dopasowanie.
10.11.2.1 Tło: przekazywanie parametrów poprzez dopasowanie #
dla wywołań funkcji, formalne parametry (wewnątrz definicji funkcji) są dopasowywane do rzeczywistych parametrów (wewnątrz wywołań funkcji). Jako przykład, weź następującą definicję funkcji i następujące wywołanie funkcji.
function
func
(
a
=
0
,
b
=
0
)
{
···
}
func
(
1
,
2
);
parametry a
i b
są ustawione podobnie do następującej destrukcji.
←
10.11.2.2 używanie move2()
#
sprawdźmy, jak działa destrukcja dla move2()
.
przykład 1. move2()
prowadzi do tego zniszczenia:
←
pojedynczy element tablicy po lewej stronie nie ma dopasowania po prawej stronie, dlatego {x,y}
jest dopasowany do wartości domyślnej, a nie do danych z prawej strony (reguły 3b, 3d) :
{
x
,
y
}
←
{
x
:
0
,
y
:
0
}
lewa strona zawiera skróty wartości właściwości, jest to skrót dla:
{
x
:
x
,
y
:
y
}
←
{
x
:
0
,
y
:
0
}
destrukcja ta prowadzi do następujących dwóch zadań (Zasady 2c, 1):
x
=
0
;
y
=
0
;
przykład 2. Przyjrzyjmy się wywołaniu funkcji move2({z:3})
, które prowadzi do następującej destrukcji:
←
po prawej stronie znajduje się element tablicy o indeksie 0. Dlatego wartość domyślna jest ignorowana, a następnym krokiem jest (reguła 3d):
{
x
,
y
}
←
{
z
:
3
}
to prowadzi do tego, że zarówno x
, jak i y
są ustawione na undefined
, co nie jest tym, czego chcemy.
10.11.2.3move1()
#
spróbujmy move1()
.
przykład 1: move1()
←
nie mamy elementu tablicy o indeksie 0 po prawej stronie i używamy wartości domyślnej (reguła 3d):
{
x
=
0
,
y
=
0
}
←
{}
lewa strona zawiera skróty wartości właściwości, co oznacza, że destrukcja ta jest równoważna:
{
x
:
x
=
0
,
y
:
y
=
0
}
←
{}
ani własność x
, ani własność y
nie mają dopasowania po prawej stronie. Dlatego używane są wartości domyślne i następująca destrukcja jest wykonywana dalej (reguła 2d):
x
←
0
y
←
0
prowadzi to do następujących zadań (zasada 1):
x
=
0
y
=
0
przykład 2: move1({z:3})
←
pierwszy element wzorca tablicy ma dopasowanie po prawej stronie i to dopasowanie jest używane do kontynuowania destrukcji (zasada 3d):
{
x
=
0
,
y
=
0
}
←
{
z
:
3
}
podobnie jak w przykładzie 1, po prawej stronie nie ma właściwości x
i y
i używane są wartości domyślne:
x
=
0
y
=
0
10.11.2.4 wniosek #
przykłady pokazują, że wartości domyślne są cechą części wzorca (właściwości obiektu lub elementów tablicy). Jeśli część nie ma dopasowania lub jest dopasowana do undefined
, to używana jest wartość domyślna. Oznacza to, że wzorzec jest dopasowywany do wartości domyślnej.