Uwaga! Trwają prace nad nową wersją serwisu. Mogą występować przejściowe problemy z jego funkcjonowaniem. Przepraszam za niedogodności!
⛔ Potrzebujesz wsparcia? Oceny CV? A może Code Review? ✅ Dołącz do Discorda!
Wyglądają tak samo – to trzy kropki – a jednak są wykorzystywane do innych celów. Teoretycznie nie trzeba znać ich nazw, by umieć je stosować, lecz warto usystematyzować swoją wiedzę zanim o rozproszenie lub parametr reszty zapyta Cię rekruter techniczny!
Rozproszenie i parametr reszty wyglądają tak samo: to trzy kropki. W pewnym uproszczeniu mają jednak „przeciwne” role, które często u osób początkujących powodują problem z nazewnictwem. Czym jest jedno, a czym drugie? Warto umieć je nie tylko stosować, ale również odróżnić – choćby po to, by nie zaliczyć wpadki na rozmowie rekrutacyjnej (np. podczas omawiania kodu w trakcie pair programmingu).
„Rozprasza” elementy tam, gdzie dostajemy je „w pakiecie” – czyli w postaci stringa, tablicy czy obiektu. Spread często używany jest np. przy tworzeniu jednej tablicy z dwóch lub łączeniu obiektów.
Przydaje się np. w pracy z Reactem przy przekazywaniu wartości między komponentami przez tzw. props. Załóżmy, że otrzymaliśmy dwa obiekty z ustawieniami dla stylów i chcemy je połączyć w jeden obiekt styles. Zrobimy to w ten sposób:
const spaceStyles = { margin: "60px", padding: "10px" }; const sizeStyles = { width: "100px", height: "150px" }; styles = { ...spaceStyles, ...sizeStyles };
Teraz obiekt styles wygląda tak (kolejność kluczy nie ma znaczenia, może się zmienić):
{ margin: "60px", padding: "10px", width: "100px", height: "150px" }
Uwaga: rozproszenie pozwala nam tworzyć nowe obiekty, ale nie pozwala mutować tych, które już mamy – oczywiście jeśli zgodnie z dobrymi praktykami stosujemy const (sprawdź przykład poniżej). Do tego nadal trzeba wykorzystywać metodę Object.assign():
const styles = { margin: "60px", padding: "10px", width: "100px", height: "150px" } const colorStyles = { color: "red", backgroundColor: "yellow" } Object.assign( styles, colorStyles );
Widzisz? W takiej sytuacji nie tworzymy nowego obiektu, lecz dodajemy nowe wartości do już istniejącego (mutujemy go). Nasz obiekt styles wygląda teraz tak:
{ margin: "60px", padding: "10px", width: "100px", height: "150px", color: "red", backgroundColor: "yellow" }
W przykładzie mamy dwa „pakiety owoców”: tablicę yellowFruit i greenFruit.
const yellowFruit = ["melon", "banana", "lemon"]; const greenFruit = ["apple", "grapes"];
Chcemy połączyć je w ogólny zbiór owoców, np. tablicę fruit. Dzięki rozproszeniu robimy to w jednej linii i zachowujemy bardzo dobrą czytelność kodu:
const fruit = [ ...yellowFruit, ...greenFruit ];
Co otrzymujemy? Tylko jedną tablicę, ponieważ wartości zgromadzone w tablicach yellowFruit i greenFruit zostały rozproszone – „pozbyliśmy się ich opakowania” w postaci tablic:
["melon", "banana", "lemon", "apple", "grapes"]
Uwaga: tutaj do mutowania tablicy (gdy nie chcemy tworzyć nowej) zastosujemy odpowiednie metody, np. .push() czy .unshift() w połączeniu z rozproszeniem:
const fruit = ["apple", "pear"]; const yellowFruit = ["melon", "banana", "lemon"]; fruit.push(...yellowFruit);
W tej sytuacji nie tworzymy nowej tablicy, lecz rozszerzamy pierwszą o nowe elementy. Tablica fruit wygląda teraz tak:
["apple", "pear", "melon", "banana", "lemon"];
Podobnie jak w przypadku destrukturyzacji, rozproszenie można zastosować także do stringu:
const word = "mouse"; const letters = [ "a", "p", ...word, "d"];
W ten sposób dodaliśmy litery do nowo utworzonej tablicy:
["a", "p", "m", "o", "u", "s", "e", "d"]
Niejednokrotnie spotkasz się z tym, że rozproszenie używane jest do tworzenia kopii tablic i obiektów, np. tak:
// kopiowanie obiektu const style = { margin: "60px", padding: "10px" } const newStyle = { ...style } // kopiowanie tablicy const numbers = [ 1, 2, 3, 4, 5 ] const newNumbers = [ ...numbers ]
Trzeba jednak pamiętać, że w przypadku obiektów dochodzi w ten sposób do utworzenia kopii płytkiej (shallow copy) – tak samo jak wtedy, gdy stosujemy metodę Object.assign(). Jeśli chcesz zgłębić ten temat, zapraszam Cię do mojego wideo, w którym omawiam płytkie i głębokie kopiowanie obiektu.
O wykorzystaniu rozproszenia podczas destrukturyzacji przeczytasz w moim artykule Czym jest destrukturyzacja w JavaScript i jak ją stosować.
Słowo klucz, które pozwoli Ci rozróżnić rest od spread, to „parametr”. Gdzie mamy parametry? Tylko podczas tworzenia funkcji (czy to w formie deklaracji funkcji czy wyrażenia funkcyjnego). Zaznaczam: tylko podczas tworzenia funkcji. Gdy wywołujemy funkcję, mamy już do czynienia z argumentami (nie parametrami!).
Przykładowo to są parametry a i b oraz c i d:
function sum( a, b ) { return a + b } const subtract = function( c, d ) { return c - d }
A to argumenty 2 i 10 oraz 10.5 i 0.5:
sum( 2, 10 ) subtract(10.5, 0.5)
Jeśli nadal ich nie rozróżniasz, zajrzyj do ostatniej sekcji mojego artykułu „Front end – pojęcia, które mylą się na początku nauki (część 1)”.
Ustaliliśmy zatem, że parametr reszty to parametr funkcji. Mówiliśmy już też, że stanowi pewnego rodzaju „przeciwieństwo” rozproszenia. W rozproszeniu mieliśmy „pakiet” wartości, które „rozrzucaliśmy”. Parametr reszty zaś działa na odwrót: zbiera takie „rozrzucone” elementy w „pakiet” – tablicę (tak, tym razem to zawsze tylko tablica).
W poniższym przykładzie mamy funkcję, która wyświetla (dodaje do elementu body) listę zakupów o konkretnej nazwie. Zwróć uwagę, że nasz parametr reszty (...products) jest ostatnim parametrem – to warunek konieczny!
function displayList(name, ...products) { const ulElement = document.createElement("ul"); ulElement.innerText = name; products.forEach(function(product) { const liElement = document.createElement("li"); liElement.innerText = product; ulElement.appendChild(liElement); }) document.body.appendChild(ulElement) }
Dzięki takiemu rozwiązaniu za jednym zamachem możemy stworzyć długa listę produktów, wpisując kolejne argumenty za nazwą listy:
displayList("Grocery", "bananas", "apples", "cheese", "crisps", "pasta")
Uruchom powyższy kod np. w JSFiddle, by sprawdzić, w jaki sposób działa.
Chcesz przetestować kod z grafiki? Możesz skopiować poniższy przykład:
function createPerson( name, ...nicknames) { let fullName = name; nicknames.forEach( nick => { fullName = fullName + ' ' + nick }) return fullName } const person = createPerson("John", "Cat", "The Greatest"); console.log(person)
Rozproszenie (spread) to wyjęcie wartości z „opakowania” (tablicy, obiektu czy stringa), by można było przekazać je gdzieś indziej.
Parametr reszty (rest) to parametr funkcji, pod który podczas wywołania funkcji możemy podstawić dowolną liczbę argumentów.
Udostępnij ten artykuł:
Potrzebujesz cotygodniowej dawki motywacji?
Zapisz się i zgarnij za darmo e-book o wartości 39 zł!
PS. Zazwyczaj rozsyłam 1-2 wiadomości na tydzień. Nikomu nie będę udostępniał Twojego adresu email.
Chcesz zostać (lepszym) programistą i lepiej zarabiać?
🚀 Porozmawiajmy o nauce programowania, poszukiwaniu pracy, o rozwoju kariery lub przyszłości branży IT!
Umów się na ✅ bezpłatną i niezobowiązującą rozmowę ze mną.
Chętnie porozmawiam o Twojej przyszłości i pomogę Ci osiągnąć Twoje cele! 🎯