Destrukturyzacja
Dane z obiektów możemy wyciągać tak jak to robiliśmy do tej pory, czyli korzystając ze składni kropki lub kwadratowych nawiasów. Możemy też skorzystać z tak zwanego przypisania destrukturyzującego, czy też destrukturyzacji, która skraca zapis.
//klasycznie
const tab = ["Ala", "Ola", "Ela"];
//klasycznie
const name1 = tab[0];
const name2 = tab[1];
//za pomocą destrukturyzacji
const [name1, name2] = tab;
const ob = {
name : "Marcin",
pet : "kot"
}
//klasycznie
const name = ob.name;
const pet = ob["pet"];
//za pomocą destrukturyzacji
const {name, pet} = ob;
Destrukturyzacja tablic
Aby stworzyć nowe zmienne na bazie danych z tablicy możemy skorzystać z zapisu:
const tab = ["Ala", "Ola", "Ela", "Fela"];
const [a, b] = tab;
console.log(a, b) //"Ala", "Ola"
Jeżeli chcielibyśmy z tablicy wyciągnąć wartości, ale z pominięciem kolejnej, wtedy musimy użyć przecinka:
const [name1, name2, , name4] = tab;
console.log(name1, name2, name4); //"Ala", "Ola", "Fela"
Podczas tworzenia zmiennych, możemy im też ustawić domyślą wartość, która zostanie użyta, jeżeli w tablicy nie będzie wartości na danym indeksie:
const tab = ["Ala", "Ola"];
const [ name1="brak", name2="brak", name3="brak" ] = tab;
console.log(name1, name2, name3); //"Ala", "Ola", "brak"
Stosując przypisanie destrukturyzacji możemy też użyć operatora rest:
const tab = [1, 2, 3, 4, 5];
const [first, ...vars] = tab;
console.log(first, vars); //1, [2, 3, 4, 5]
A także działać na tablicach zwracanych przez funkcję:
function generateArr(min=0, max=10, lng=5) {
const tab = [];
for (let i=0; i<lng; i++) {
tab.push(Math.floor(Math.random()*(max-min+1)+min));
}
return tab;
}
const [a, b, c] = generateArr();
Przypisanie takie możemy też zastosować przy zamianie miejscami wartości zmiennych:
let a = 1;
let b = 5;
[a, b] = [b, a];
console.log(a); // 5
console.log(b); // 1
Destrukturyzacja obiektów
Przypuśćmy, że mamy obiekt:
const obj = {
first_name : "Marcin",
last_name : "Kowalski",
age : 10
}
Jeżeli teraz chciałbym, z tego obiektu wyciągnąć dane i podstawić je pod zmienne mógłbym to zrobić w klasyczny sposób:
const obj = {
first_name : "Marcin",
last_name : "Kowalski",
age : 10
}
const name = obj.first_name;
const surname = obj.last_name;
const age = obj.age;
Ale i za korzystając z przypisania destrukturyzacji:
const obj = {
first_name : "Marcin",
last_name : "Kowalski",
age : 10
}
const { first_name, last_name, age } = obj;
Jeżeli w danym obiekcie nie będzie właściwości o danej nazwie, pod naszą zmienną zostanie podstawiona wartość undefined
.
Żeby temu zapobiec, naszym zmiennym możemy ustawić domyślne wartości:
const obj = {
first_name : "Marcin",
last_name : "Kowalski"
}
const {
first_name = "brak",
last_name = "brak",
favoritePet = "brak"
} = obj;
console.log(first_name); //Marcin
console.log(last_name); //Kowalski
console.log(favoritePet); //"brak"
Gdybyś chciał stworzyć zmienne o nowych nazwach, musisz użyć znaku dwukropka:
const obj = {
first_name : "Marcin",
last_name : "Kowalski",
}
const {
first_name : name = "brak",
last_name : surname = "brak",
favoritePet : pet = "brak"
} = obj;
console.log(name); //Marcin
console.log(surname); //Kowalski
console.log(pet); //"-"
Destrukturyzacja w iteracji
Destrukturyzacja idealnie sprawdza się w przypadku iterowania po danych:
.fetch(.....)
.then(result => result.json())
.then(result => {
//działamy na pobranych użytkownikach
for (const el of result.users) {
const {
name = "",
surname = "",
email = "",
plan = "basic"
role = "user",
www = ""
} = el;
console.log(surname, name, email, plan, role, www);
}
});
Destrukturyzacja i parametry funkcji
Bardzo przydatnym manewrem jest zastosowanie destrukturyzaji w przypadku parametrów funkcji.
Wszędzie tam, gdzie ktoś (w tym silnik Javascript) przekaże ci jakiś obiekt czy tablicę, możesz używać desktruturyzacji do wyciągania danych z jego wnętrza:
Zamiast więc działać bezpośrednio na danej zmiennej:
const buttons = document.querySelectorAll("button");
//zamiast
buttons.forEach(el => {
console.log(`Tekst elementu to ${el.innerText} a jego id to ${el.id}`);
})
Mogę wyciągnąć odpowiednie dane, dzięki czemu mój kod się uprości:
const buttons = document.querySelectorAll("button");
buttons.forEach(({innerText : text, id}) => {
console.log(`Tekst elementu to ${text} a jego id to ${id}`);
});
Dzięki temu zamiast
function showUser(ob) {
console.log(ob.name);
console.log(ob.surname)
}
const user = {
name : "Marcin",
surname : "Nowak"
}
showUser(user)
mogę:
function showUser({name, surname}) {
console.log(name);
console.log(surname)
}
const user = {
name : "Marcin",
surname : "Nowak"
}
showUser(user);
Jak widzisz przekazałem do funkcji obiekt, z którego potem wyciągnąłem odpowiednie wartości.
W obiektach kolejność kluczy nie ma znaczenia, dzięki czemu mogę przekazywać do funkcji dane nie zważając na kolejność parametrów:
//mam funkcję która wymaga kilku parametrów
function print(name, speed, color, food) {
//...
}
//mam kilka zmiennych, które chcę do niej przekazać
const name = "Szamson";
const speed = 10000;
const color = "brown";
const food = "mięso";
const type = "dog";
const profession = "fight with bad guys";
//w przypadku zwykłej funkcji muszę pamiętać kolejność parametrów
print(name, speed, color, food);
Zamiast pamiętania kolejności, mogę skróconym zapisem stworzyć obiekt i przekazać go do funkcji:
function print({name, speed, color, food}) {
//...
}
const name = "Szamson";
const speed = 10000;
const color = "brown";
const food = "mięso";
const type = "dog";
const profession = "fight with bad guys";
print({name, food, speed, color, type});
Destrukturyzacja i rest
Od ECMAScript 2018 istniej też możliwość zastosowania destrukturyzacji wraz z spread syntax, co przydaje się do tworzenia obiektów z pominięciem danych właściwości:
const ob = {
name : "Piotrek",
age : 20,
surname : "Nowak",
pet : "pies"
}
const {pet, ...obWithoutPet} = ob;
console.log(pet); //"pies"
console.log(obWithoutPet); //obiekt bez właściwości pet
const carData = {
brand : "BMW",
color: "red",
maxSpeed : 260,
owner: "Jan Nowak",
ownerAge : 30
}
const {owner, ownerAge, ...car} = carData;
console.log(car); //car bez właściwości owner i ownerAge
Bardziej skomplikowana struktura
Jeżeli za pomocą destrukturyzacji chcemy wyciągać zagnieżdżone dane, wtedy w naszym wzorze powinniśmy odwzorować wygląd struktury obiektu:
const myObj = {
first_name : "Karol",
last_name : "Nowak",
role : "driver",
pets: ["pies", "kot"],
car : {
name : "Honda",
year: 2002,
type : "hatchback"
}
}
const {
first_name: name,
last_name : surname,
role,
pets : [
pet1,
pet2
],
car : {
name : carName,
year : carYear,
type : carType
}
} = myObj || {}
Zauważ, że nasz wzorzec postawiłem pod myObj lub pusty obiekt. Dzięki temu zabezpieczam się na wypadek, gdyby nie było myObj w ogóle.