Destrukturyzacja w pigułce

destrukturyzacja

Jedną z moich ulubionych funkcjonalności w języku Javascript jest destrukturyzacja wprowadzona w ES6. Pozwala na wyciąganie danych z tablic lub obiektów do zmiennych korzystając ze specjalnej składni w sposób deklaratywny i czytelny.

Problem, który rozwiązuje destrukturyzacja

Aby zrozumieć, dlaczego ta funkcjonalność jest tak lubiana i tak często używana, warto przypomnieć sobie, jak dzisiejszy proces destrukturyzacji wyglądał w przeszłości.

// Before array destructuring
var arr = [1, 2, 3];
var first = arr[0];
var second = arr[1];
var third = arr[2];

// Before object destructuring
var person = {
  name: 'Darek',
  contact: {
    email: 'example@example.com'
  }
};
var name = person.name;
var email = person.contact.email;

Taki zapis jest bardzo imperatywny. Widzimy tutaj sekwencje instrukcji przypisujących wartości znajdujące się w tablicy lub obiekcie do zmiennych. Widzimy sposób realizacji, podczas gdy destrukturyzacja pozwala na określenie efektu końcowego bez martwienia się krokami potrzebnymi do wykonania zadania.

Destrukturyzacja tablic

Składnia destrukturyzacji przypomina nieco deklarację tablicy, z tym że wykonujemy ją po lewej stronie znaku =, gdzie określamy nazwy kolejnych zmiennych, do których zostaną przypisane kolejne elementy tablicy.

const arr = [1, 2 ,3];
const [first, second, third] = arr;
console.log(first, second, third) // 1 2 3

Aby pominąć element, wystarczy podczas destrukturyzacji wstawić przecinek w miejscu elementu do pominięcia.

const arr = [1, 2 ,3];
const [,, third] = arr;
console.log(third) // 3

Próba pobrania nieistniejącego elementu zwraca undefined.

const arr = [1, 2];
const [first, second, nonExistent] = arr;
console.log(nonExistent); // undefined

Mamy możliwość głębokiej destrukturyzacji tablic. Jest to jedna z funkcji, która stosuję bardzo rzadko ze względu nieczytelny zapis.

const arr = [1, [2, [3]]];
const [first, [second, [third]]] = arr;
console.log(first, second, third); // 1, 2, 3

Istnieje możliwość definiowania wartości domyślnych dla zmiennych. Są one wykorzystywane wtedy, gdy do zmiennej ma zostać przypisana wartość undefined.

const arr = [undefined, null, 10];
const [first = 1, second = 2, third = 3] = arr;
console.log(first, second, third); // 1 null 10

Dzięki operatorowi ...rest jesteśmy w stanie zebrać pozostałe elementy w tablicy. Istotne jest to, że ...rest musi znajdować się jako ostatni zmienna w destrukturyzacji.

const arr = [1, 2, 3];
const [first, ...otherNumbers] = arr;
console.log(first); // 1
console.log(otherNumbers); // [2, 3]
const [...test, last] = arr; // Error: Rest must be last element

Jednym z zastosowań operatora ...rest jest tworzenie funkcji przyjmujących nieograniczoną ilość argumentów.

const logNumbers => (...numbersToLog) => {
  console.log(numbersToLog);
};

logNumbers(); // []
logNumbers(1, 2); // [1, 2]
logNumbers(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]

Destrukturyzacja obiektów

Aby wyciągnąć atrybuty z obiektu, deklarujemy ich nazwy umieszczając je w klamrach po lewej stronie znaku =.

const person = {
  name: 'John',
  contact: {
    email: 'example@example.com'
  }
};

const {name, contact} = person;
console.log(name, contact); // John, { email: 'example@example.com' }

Aby pominąć dany atrybut, wystarczy go nie deklarować.

const person = {
  name: 'John',
  contact: {
    email: 'example@example.com'
  }
};

const {name} = person;
console.log(name); // John

Podobnie jak w przypadku tablic, próba pobrania nieistniejącego atrybutu zwróci undefined.

const person = {
  name: 'John',
  contact: {
    email: 'example@example.com'
  }
};

const {age} = person;
console.log(age); // undefined

Również w przypadku obiektów mamy możliwość głębokiej destrukturyzacji. W przeciwieństwie do tablic pobieranie atrybutów z wnętrza obiektu jest bardzo czytelne. Zauważ, że dla obiektów pośrednich nie zostają stworzone zmienne (patrz contact), ale pomimo tego i tak jesteśmy w stanie uzyskać do nich dostęp, jeśli jednocześnie je zadeklarujemy i dokonamy na nich destrukturyzacji (patrz address).

const person = {
  name: 'John',
  contact: {
    email: 'example@example.com',
    address: {
      city: 'New York'
    }
  }
};

const {
  name, 
  contact: {
    email,
    address,
    address: {
      city
    }
  }
} = person;

console.log(name, email, city); // John example@example.com New York
console.log(address); // { city: 'New York' }
console.log(contact); // Error: contact is not defined

Tak jak w przypadku tablic, tak i tutaj możemy zadeklarować domyślną wartość dla zmiennej.

const person = {
  name: 'John'
};

const {name, age = 22} = person;
console.log(name, age); // John, 22

Jeśli chcemy, żeby zmienna miała inną nazwę niż pobierany atrybut, wystarczy, że po nazwie atrybutu postawimy : i podamy nową nazwę zmiennej.

const person = {
  name: 'John'
};

const {name: firstName} = person;
console.log(firstName); // John

Na koniec chciałbym Ci pokazać w jaki sposób jednocześnie zadeklarować wartość domyślną i zmienić nazwę zmiennej.

const person = {
  name: 'John'
};

const {surname: lastName = 'Doe'} = person;
console.log(lastName); // Doe

W przypadku obiektów operator ...rest umożliwia zebranie pozostałych atrybutów obiektu.

const person = {
  name: 'John',
  surname: 'Doe',
  age: 22
};

const {age, ...fullName} = person;
console.log(age, fullName); // 22 { name: 'John', surname: 'Doe' }

Destrukturyzacja parametrów funkcji

Na końcu chciałbym wspomnieć o tym, że destrukturyzacje możemy zastosować podczas definiowania parametrów funkcji.

const person = {
  name: 'John',
  surname: 'Doe'
}

// Object parameter destructuring
function introducePerson({name, surname}) {
  console.log(`My name is ${name} ${surname}`);
}

introducePerson(person); // My name is John Doe

// ======================

const tuple = ['age', 20];

// Array parameter destructuring
function createObjectFromTuple([key, value]) {
  return {
    key: value
  };
}

console.log(createObjectFromTuple(tuple)); // { age: 20 }

Podsumowanie

Destrukturyzacja to dosyć prosta, ale niesamowicie pomocna funkcjonalność, która pokazuje w jakim kierunku powinno iść programowanie. Jeśli potrzebujesz praktyki, to przygotowałem ćwiczenie wymagające poprawy kodu w taki sposób, aby używał destrukturyzacji.

Pobierz darmowy ebook zawierający 20 pytań, które możesz usłyszeć na rozmowie kwalifikacyjnej