Parametry resztowe i domy┼Ťlne

> Dodaj do ulubionych

ES6 bez tajemnic to cykl artyku┼é├│w po┼Ťwi─Öconych nowym sk┼éadnikom j─Özyka JavaScript, kt├│re pojawi┼éy si─Ö w 6. edycji standardu ECMAScript, w skr├│cie ES6.

Dzisiejszy artyku┼é po┼Ťwi─Öcony jest dw├│m sk┼éadnikom, dzi─Öki kt├│rym programi┼Ťci JavaScriptu b─Öd─ů mogli wyra┼╝a─ç w swoich funkcjach wi─Öcej ni┼╝ dotychczas ÔÇô to parametry resztowe i parametry domy┼Ťlne.

Parametry resztowe

Podczas tworzenia interfejsu API zwykle potrzebna jest funkcja wariadyczna (ang. variadic function), czyli funkcja przyjmuj─ůca dowoln─ů liczb─Ö argument├│w. Na przyk┼éad metoda String.prototype.concat mo┼╝e przyj─ů─ç dowoln─ů liczb─Ö argument├│w ┼éa┼äcuchowych. Wprowadzone w ES6 parametry resztowe umo┼╝liwiaj─ů pisanie funkcji wariadycznych w nowy spos├│b.

Zilustruj─Ö to zagadnienie, pisz─ůc prost─ů funkcj─Ö wariadyczn─ů o nazwie containsAll, kt├│ra sprawdzi czy dany ┼éa┼äcuch zawiera okre┼Ťlone pod┼éa┼äcuchy. Przyk┼éadowo wywo┼éanie funkcji containsAll("banana", "b", "nan") zwr├│ci warto┼Ť─ç true, a containsAll("banana", "c", "nan") ÔÇö false.

Oto standardowy spos├│b na zaimplementowanie funkcji containsAll:

function containsAll(haystack) {
  for (var i = 1; i < arguments.length; i++) {
    var needle = arguments[i];
    if (haystack.indexOf(needle) === -1) {
      return false;
    }
  }
  return true;
}

W powy┼╝szej implementacji wykorzystywany jest magiczny, przypominaj─ůcy tablic─Ö obiekt arguments, w kt├│rym zawarte s─ů parametry przekazywane funkcji. Zaprezentowany kod spe┼énia swoje zadanie, jednak m├│g┼éby by─ç bardziej czytelny. Lista parametr├│w funkcji zawiera tylko jeden element ÔÇö haystack. Rzut oka na funkcj─Ö nie wystarczy zatem, by stwierdzi─ç, ┼╝e wbrew pozorom przyjmuje ona kilka argument├│w. Ponadto nale┼╝y pami─Öta─ç, by iteracyjne przegl─ůdanie obiektu arguments rozpocz─ů─ç od indeksu o warto┼Ťci 1, a nie 0, poniewa┼╝ element arguments[0] odpowiada argumentowi haystack. Je┼Ťli natomiast chcieliby┼Ťmy doda─ç jeszcze jeden parametr przed argumentem haystack lub po nim, musieliby┼Ťmy r├│wnie┼╝ zaktualizowa─ç p─Ötl─Ö for. Parametry resztowe rozwi─ůzuj─ů oba te problemy. Oto naturalna implementacja funkcji containsAll w ES6, wykorzystuj─ůca parametr resztowy:

function containsAll(haystack, ...needles) {
  for (var needle of needles) {
    if (haystack.indexOf(needle) === -1) {
      return false;
    }
  }
  return true;
}

Powy┼╝sza wersja funkcji dzia┼éa identycznie jak jej poprzedniczka, jednak zawiera specjaln─ů sk┼éadni─Ö ...needles. Sprawd┼║my jak zadzia┼éa dla wywo┼éania containsAll("banana", "b", "nan"). Jak zwykle, argumentowi haystack przypisywany jest pierwszy z przekazanych parametr├│w, czyli "banana". Wielokropek przed argumentem needles wskazuje, ┼╝e jest to parametr resztowy. Wszystkie pozosta┼ée przekazywane parametry s─ů umieszczone w tablicy i przypisane zmiennej needles. W naszym przyk┼éadowym wywo┼éaniu parametrowi needles przypisana zostaje tablica ["b", "nan"]. Wykonanie funkcji przebiega nast─Öpnie tak jak zwykle. (Zwr├│─ç uwag─Ö, ┼╝e wykorzystali┼Ťmy p─Ötl─Ö for-of z ES6).

Tylko ostatni parametr funkcji mo┼╝e by─ç oznaczony jako parametr resztowy. Poprzedzaj─ůce go parametry s─ů przypisywane przy wywo┼éaniu tak jak zwykle. Wszelkie ÔÇ×dodatkoweÔÇŁ argumenty s─ů natomiast umieszczane w tablicy i przypisywane parametrowi resztowemu. W przypadku braku dodatkowych argument├│w parametrowi resztowemu przypisana zostaje po prostu pusta tablica, nigdy warto┼Ť─ç undefined.

Parametry domy┼Ťlne

W przypadku funkcji cz─Östo bywa tak, ┼╝e przekazanie wszystkich mo┼╝liwych parametr├│w przez kod inicjuj─ůcy wywo┼éanie nie jest wymagane. Istniej─ů sensowne parametry domy┼Ťlne, z kt├│rych mo┼╝na skorzysta─ç w miejsce nieprzekazywanych parametr├│w. W JavaScripcie od zawsze parametry domy┼Ťlne s─ů sztywne ÔÇô wszelkie braki warto┼Ťci domy┼Ťlnie zape┼énia si─Ö warto┼Ťci─ů undefined. W ES6 pojawia si─Ö jednak spos├│b na okre┼Ťlenie dowolnej warto┼Ťci parametr├│w domy┼Ťlnych.

Oto przyk┼éad (odwrotne apostrofy oznaczaj─ů ┼éa┼äcuchy szablonowe, kt├│re omawiali┼Ťmy w poprzednim artykule):

function animalSentence(animals2="tygrysy", animals3="nied┼║wiedzie") {
    return `Lwy i ${animals2} i ${animals3}! O matko!`;
}

Dla ka┼╝dego parametru po znaku = nast─Öpuje wyra┼╝enie okre┼Ťlaj─ůce domy┼Ťln─ů warto┼Ť─ç tego parametru, kt├│ra zostanie wykorzystana, je┼Ťli nie kod inicjuj─ůcy wywo┼éanie przeka┼╝e czego┼Ť innego. Funkcja animalSentence() zwr├│ci zatem ┼éa┼äcuch "Lwy i tygrysy i nied┼║wiedzie! O matko!" , funkcja animalSentence("s┼éonie") zwr├│ci ┼éa┼äcuch "Lwy i s┼éonie i nied┼║wiedzie! O matko!" , a animalSentence("s┼éonie", "wieloryby") zwr├│ci ┼éa┼äcuch "Lwy i s┼éonie i wieloryby! O matko!" .

Istnieje kilka szczeg├│lnych cech parametr├│w domy┼Ťlnych:

  • W przeciwie┼ästwie do analogicznego rozwi─ůzania w Pythonie, w ES6 wyra┼╝enia o warto┼Ťci domy┼Ťlnej s─ů przetwarzane w czasie wywo┼éania funkcji od lewej. Oznacza to r├│wnie┼╝, ┼╝e wyra┼╝enia domy┼Ťlne mog─ů przyj─ů─ç warto┼Ť─ç przypisanych wcze┼Ťniej parametr├│w. Mogliby┼Ťmy wi─Öc napisa─ç jeszcze bardziej wymy┼Ťln─ů funkcj─Ö, na przyk┼éad:
    function animalSentenceFancy(animals2="tygrysy",
        animals3=(animals2 == "niedzwiedzie") ? "lwy morskie" : "niedzwiedzie")
    {
      return `Lwy i ${animals2} i ${animals3}! O matko!`;
    }

    W takim przypadku funkcja animalSentenceFancy(„nied┼║wiedzie”) zwr├│ci ┼éa┼äcuch „Lwy i nied┼║wiedzie i lwy morskie. O matko!”.

  • Przekazanie warto┼Ťci undefined traktowane jest jak nieprzekazanie niczego, dlatego te┼╝ wynikiem funkcji animalSentence(undefined, "jednoro┼╝ce") b─Ödzie ┼éa┼äcuch "Lwy i tygrysy i jednoro┼╝ce! O matko!" .
  • Parametr bez okre┼Ťlonej warto┼Ťci domy┼Ťlnej automatycznie przyjmuje warto┼Ť─ç domy┼Ťln─ů undefined, a wi─Öc funkcja:
    function myFunc(a=42, b) {...}

    jest dopuszczalna w takiej postaci i jest r├│wnowa┼╝na z

    function myFunc(a=42, b=undefined) {...}

Koniec z obiektem arguments

Jak zd─ů┼╝yli┼Ťmy si─Ö przekona─ç, parametry resztowe i domy┼Ťlne mo┼╝na stosowa─ç zamiast obiektu arguments, a pozbycie si─Ö go zwykle sprawia, ┼╝e kod staje si─Ö czytelniejszy. Opr├│cz negatywnego wp┼éywu na czytelno┼Ť─ç kodu, jego magiczne w┼éa┼Ťciwo┼Ťci przysparzaj─ů tak┼╝e problem├│w w optymalizacji wirtualnych maszyn JavaScriptu.

Mo┼╝na mie─ç nadziej─Ö, ┼╝e parametry resztowe i domy┼Ťlne zupe┼énie zast─ůpi─ů obiekt arguments. Zosta┼éy ju┼╝ poczynione pewne kroki w tym kierunku ÔÇô w funkcjach wykorzystuj─ůcych parametry resztowe lub domy┼Ťlne nie mo┼╝na u┼╝ywa─ç obiektu arguments. Obiekt arguments nie przestanie by─ç obs┼éugiwany w najbli┼╝szej przysz┼éo┼Ťci, a mo┼╝e nawet nigdy, lecz preferowane jest, tam gdzie to mo┼╝liwe, zast─Öpowanie go parametrami resztowymi lub domy┼Ťlnymi.

Obs┼éuga parametr├│w resztowych i domy┼Ťlnych w przegl─ůdarkach

Parametry resztowe i domy┼Ťlne s─ů obs┼éugiwane w Firefoksie pocz─ůwszy od wersji 15.

Niestety, p├│ki co jest to jedyna oficjalna przegl─ůdarka obs┼éuguj─ůca te sk┼éadniki ES6. W silniku V8 wprowadzono niedawno eksperymentaln─ů obs┼éug─Ö parametr├│w resztowych, a aktualnie trwaj─ů prace nad implementacj─ů parametr├│w domy┼Ťlnych. Pr├│ba implementacji parametr├│w resztowych i domy┼Ťlnych zosta┼éa r├│wnie┼╝ podj─Öta w komponencie JSC.

Z parametr├│w domy┼Ťlnych mo┼╝na jednak zacz─ů─ç korzysta─ç ju┼╝ teraz, poniewa┼╝ s─ů one obs┼éugiwane zar├│wno w kompilatorze Babel jak i Traceur.

Podsumowanie

Cho─ç teoretycznie parametry resztowe i domy┼Ťlne nie wzbogacaj─ů funkcjonalno┼Ťci kodu, pomagaj─ů pisa─ç bardziej ekspresyjne i czytelniejsze deklaracje funkcji JS. Weso┼éego wywo┼éywania!

Adnotacja: podzi─Ökowania dla Benjamina Petersona za zaimplementowanie wymienionych sk┼éadnik├│w w Firefoksie, za ca┼éy jego wk┼éad w ten projekt i oczywi┼Ťcie za niniejszy artyku┼é.

W nast─Öpnym artykule przedstawimy kolejny prosty, elegancki i praktyczny w codziennym u┼╝ytku element ES6. Bazuje on na znanej nam sk┼éadni s┼éu┼╝─ůcej do pisania tablic i obiekt├│w, kt├│ra zostaje postawiona na g┼éowie. W rezultacie otrzymujemy nowy, zwi─Öz┼éy spos├│b na rozk┼éadanie tablic i obiekt├│w na cz─Ö┼Ťci pierwsze. Co to oznacza? Po co mieliby┼Ťmy rozk┼éada─ç obiekty? Odpowied┼║ na to pytanie poznasz w kolejnym artykule, w kt├│rym in┼╝ynier z Mozilli Nick Fitzgerald szczeg├│┼éowo przedstawi zagadnienie destrukturyzacji w ES6.

Autor: Jason Orendorff

Źródło: https://hacks.mozilla.org/2015/05/es6-in-depth-rest-parameters-and-defaults/

Tłumaczenie: Joanna Liana

Tre┼Ť─ç tej strony jest dost─Öpna na zasadach licencji CC BY-SA 3.0