Destrukturyzacja obiektów

Dekompozycja (zwana też destrukturyzacją) to nowa funkcjonalność w ES6, która polega na wyciąganiu zmiennych z jakiejś struktury - np. z obiektów lub tablic.

Dekompozycja obiektów

Przypuśćmy, że właśnie pobraliśmy za pomocą AJAX obiekt z danymi.


const myObject = {
    name : "Marcin",
    surname : "Kowalski",
    age : 10
}

Jeżeli teraz chciałbym, z tego obiektu wyciągnąć dane i podstawić je pod zmienne:


const name = myObject.name;
const surname = myObject.surname;
const age = myObject.age;

W ES6 możemy sobie to uprościć stosując destrukturyzację:


const { name, surname, age } = myObject;

To co napisaliśmy po lewej stronie przypomina obiekt, ale nim nie jest. Jest to wzór, pod który następnie podstawiamy jakiś obiekt (u nas myObject).
Między klamrami podajemy nazwy zmiennych, pod które podstawione zostaną właściwości o takich samych nazwach. Jeżeli danej właściwości w podstawionym obiekcie nie będzie, wtedy pod daną zmienną zostanie podstawione undefined:


const { name, surname, age, favoritePet } = myObject;

console.log(name); //Marcin
console.log(surname); //Kowalski
console.log(age); //10
console.log(favoritePet); //undefined

W powyższym przykładzie tworzymy zmienne o takich samych nazwach jak właściwości myObject. Gdybyś chciał stworzyć zmienne o innych nazwach, musisz użyć znaku dwukropka:


const {
    name: newName,
    surname: newSurname,
    age,
    favoritePet
} = myObject;

console.log(newName); //Marcin
console.log(newSurname); //Kowalski
console.log(age); //10
console.log(favouritePet); //undefined

Dodatkowo tworząc wzorzec, możemy danym zmiennym przypisać domyślne wartości, które zostaną użyte, jeżeli danej właściwości w podstawianym obiekcie nie będzie:


const {
    name: newName,
    surname: newSurname,
    age = 14,
    favoritePet = "Szamson"
} = myObject;

console.log(newName); //Marcin
console.log(newSurname); //Kowalski
console.log(age); //10 - bo właściwość istnieje
console.log(favouritePet); //Szamson - została użyta domyślna

Ale po co to się może przydać? Przede wszystkim tak jak wyżej - do wyciągania zmiennych z obiektów. Wyobraź sobie że chcesz wziąć coś z obiektu, a całą resztę zostawić w spokoju. Tworzysz więc szybki wzór, podstawiasz pod dany obiekt i włala. Cała reszta Cię nie interesuje.


const { url, print } = uberBigObjectWithMilionPropertiesAndMethods;

Pamiętaj też, że taki wzór możemy używać dla wielu obiektów. Wyobraź sobie, że robisz pętlę po pobranej tabeli użytkowników.
Każdego użytkownika podstawiasz pod wzór, a następnie działasz na zmiennych. Nie każdy użytkownik ma swój email, nie każdy ma swoją stronę www, ale to niczemu nie przeszkadza, bo w razie czego wzór dobierze domyślne wartości:


.fetch(.....)
.then(result => result.json())
.then(result => {
    //działamy na pobranych użytkownikach
    result.users.forEach(el => {
        const {
            name = "",
            surname = "",
            email = "",
            plan = "basic"
            role = "user",
            www = "http://"
        } = el;

        console.log(surname, name, email, plan, role, www);
    });
});

Innym bardzo ciekawym zastosowaniem destrukturyzacji jest połączenie jej z spread operatorem. Wyobraź sobie, że masz obiekt. Chciałbyś utworzyć nowy obiekt, ale bez jakiś 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 car = {
    brand : "BMW",
    color: "red",
    maxSpeed : 260,
    owner: "Jan Nowak",
    ownerAge : 30
}

const {owner, ownerAge, ...car} = carData;

console.log(car); //wypisze car bez właściwości owner i ownerAge

Dekompozycja tablic

Podobnymi zasadami rządzi się destrukturyzacja tablic. Są małe różnice, ale ogólna zasada jest podobna.

Przypuśćmy, że mamy tablicę, z której chcielibyśmy pobrać wartości:


const tab = [1, 2, 3, 4];

Jeżeli teraz chciałbym pobrać z tej tablicy 2 pierwsze wartości to użył bym zapisu:


const tab = [1, 2, 3, 4];

//klasycznie
const a = tab[0];
const b = tab[1];

//za pomocą destrukturyzacji
[a, b] = tab;

Jeżeli chcielibyśmy z tablicy wyciągnąć wartości, ale z pominięciem kolejnej, wtedy musimy użyć przecinka:


const tab = [1, 2, 3, 4];

[a, b, , c] = tab;

console.log(a, b, c); //1, 2, 4

Tak samo jak w przypadku destrukturyzacji obiektów, tworzymy jakiś wzór pod które potem podstawiana jest tablica.

Podobnie też możemy definiować domyślne wartości:


const tab = [1, 2, , 4];

[a, b, c=5] = tab;

console.log(a, b, c); //1, 2, 5

Co ciekawe, przy destrukturyzacji tablic możemy też użyć operatora rest:


const tab = [1, , 3, 4, 5];

[a, ...r] = tab;

console.log(a, r); //1, [undefined, 3, 4, 5]

Bardziej skomplikowana struktura

Przypuśćmy, że mamy obiekt użytkownika, który chcemy poddać destrukturyzacji.

Znowu - załóżmy, że całość wykonywana jest w pętli po tablicy użytkowników, które wczytaliśmy z json z serwera. W poniższym przykładzie skupiamy się na pojedynczym użytkowniku.


const myObj = {
    name : "Marcin",
    surname : "Domański",
    role : "webmaster",
    pets: ["pies", "kot"],
    car : {
        name : "Honda",
        year: 2002,
        type : "hatchback"
    }
}

Z destrukturyzacją name, surname, role i pets nie będzie problemu. Ale jak poddać destrukturyzacji bardziej skomplikowane struktury? Musimy we wzorze określić ich wygląd, czyli jeżeli poddajemy destrukturyzacji tabele w obiekcie, musimy w naszym wzorze stworzyć odzwierciedlenie takiej tabeli w obiekcie. To samo tyczy się obiektów w obiektach:


const {
    name, //nie chcemy zmieniać tej zmiennej
    surname, //tej tez nie
    role,
    pets : [
        pet1,
        pet2
    ],
    car : {
        name : carName,
        year : carYear,
        type : carType
    }
} = myObj || {}

Zauważ że nasz wzorzec postawiłem pod myObj || pusty obiekt. Dzięki temu zabezpieczam się na wypadek, gdyby nie było myObj

Trening czyni mistrza

Poniżej zamieszczam kilka zadań, które w ramach ćwiczenia możesz wykonać.

  1. Mamy obiekt:
    
                const obj = {
                    name : "Marcin",
                    surname : "Kowalski",
                    age : 20
                }
                

    Za pomocą destrukturyzacji utwórz 3 zmienne: name, surname i userAge

    
                const obj = {
                    name : "Marcin",
                    surname : "Kowalski",
                    age : 20
                }
    
                const {name, surname, age : userAge} = obj;
    
                console.log(name, surname, userAge);
                
  2. Mamy tablicę:
    
                const tab = [1,2,3,4,5];
            
    Za pomocą destrukturyzacji pobierz pierwszą, drugą i czwartą wartość z tej tablicy i podstaw je pod zmienne a, b, c
    
                    const tab = [1,2,3,4,5];
    
                    const [a, b, , c] = tab;
    
                    console.log(a, b, c);