Parametry vs argumenty
Dwa słowa, które ciągle się mylą. Parametr to nazwa w definicji funkcji. Argument to wartość, którą przekazujesz przy wywołaniu. Ta sama idea co w Pythonie i większości innych języków:
a i b to parametry. 2 i 3 to argumenty. JavaScript wiąże je według pozycji: pierwszy argument z pierwszym parametrem i tak dalej. Różnica jest niewielka, ale tego słownictwa używają komunikaty o błędach i MDN.
JavaScript luźno podchodzi do liczby argumentów
W przeciwieństwie do wielu języków JavaScript nie przejmuje się, gdy przekażesz za mało albo za dużo argumentów. Brakujące parametry stają się undefined. Nadmiarowe są po cichu ignorowane:
Pierwsze wywołanie wypisuje Hello, Ada undefined: last nie dostał wartości, więc jest undefined, a template literals chętnie to wstawiają. Bez błędu, bez ostrzeżenia. Ta pobłażliwość czasem się przydaje, a czasem jest źródłem błędów, i właśnie dlatego istnieją parametry domyślne.
Ustawianie wartości domyślnej
Po nazwie parametru wstaw = i wartość. Jeśli wywołujący nie przekaże tego argumentu (albo przekaże undefined), wkracza wartość domyślna:
Wszystkie trzy wywołania działają. Pierwsze i trzecie uruchamiają wartość domyślną, drugie używa przekazanej wartości. To składnia ES6: przed 2015 rokiem trzeba było pisać w ciele funkcji name = name || "friend", co miało własne błędy przy wartościach falsy, takich jak 0 i "".
Wartości domyślne mogą być dowolnym wyrażeniem, nie tylko literałem:
Wyrażenie jest obliczane przy każdym wywołaniu, a nie raz przy definiowaniu funkcji. Nie ma więc pułapki mutowalnych wartości domyślnych, jaką ma Python: każde wywołanie dostaje świeże new Date().
Wartość domyślną uruchamia tylko undefined
To zasada, która zaskakuje. Wartości domyślne działają, gdy argument to undefined, a nie gdy jest falsy, i nie wtedy, gdy to null:
Tylko ostatnie wywołanie używa "friend". Jawne przekazanie null znaczy "wartość to null" i JavaScript bierze cię za słowo. To samo dotyczy pustych stringów i zer: to wartości, a nie brakujące argumenty.
Jeśli chcesz traktować null tak samo jak brak argumentu, musisz to obsłużyć samodzielnie:
Operator ?? (nullish coalescing) traktuje i null, i undefined jako "brak". Więcej o nim w jednym z kolejnych rozdziałów.
Wartości domyślne mogą korzystać z wcześniejszych parametrów
Parametry są obliczane od lewej do prawej, więc późniejsza wartość domyślna może używać każdego parametru, który był przed nią:
Wywołanie z jednym argumentem daje sześcian. Dwa argumenty dają graniastosłup o kwadratowej podstawie. Kierunek ma znaczenie: nie możesz odwołać się do parametru, który nie został jeszcze zadeklarowany:
function bad(a = b, b = 1) {
return a + b;
}
bad(); // ReferenceError: Cannot access 'b' before initialization
Te same zasady co przy zmiennych zadeklarowanych przez let: użycie przed deklaracją to błąd.
Wartości domyślne a destrukturyzacja
Możesz jednocześnie destrukturyzować parametry i nadawać im wartości domyślne. To popularny wzorzec dla argumentów w postaci "obiektu opcji":
Działają tu dwie warstwy wartości domyślnych. Wewnętrzne (role = "member", active = true) uzupełniają brakujące właściwości. Zewnętrzne = {} obsługuje przypadek, w którym wywołujący w ogóle nie przekaże argumentu: bez niego createUser() próbowałoby destrukturyzować undefined i rzuciłoby błąd.
Na początku ten wzorzec wygląda gęsto, ale jest wszędzie we współczesnym kodzie JavaScript. Gdy oko zacznie rozpoznawać { ... } = {} jako "opcje z wartościami domyślnymi", czyta się go szybko.
Pomijanie środkowego argumentu
JavaScript nie ma argumentów nazwanych jak w Pythonie. Żeby pominąć środkowy parametr i użyć jego wartości domyślnej, przekazujesz jawnie undefined:
Przekazanie undefined jako prefix zachowuje wartość domyślną. To brzydkie. Jeśli często piszesz undefined w wywołaniach, to sygnał, żeby przejść na obiekt opcji:
Teraz wywołujący nazywa to, co chce nadpisać, a kolejność nie ma znaczenia.
Wartości domyślne nie wliczają się do length
Drobny szczegół, który rzadko ma znaczenie, ale czasem wprowadza w błąd. Właściwość length funkcji podaje liczbę parametrów przed pierwszym parametrem z wartością domyślną:
Biblioteki, które analizują funkcje (na przykład niektóre narzędzia do testów i wstrzykiwania zależności), używają length do liczenia "wymaganych" parametrów. Dobrze wiedzieć, że taka zasada istnieje, ale nie warto jej zapamiętywać, chyba że piszesz tego typu narzędzie.
Dalej: rest i spread
Wartości domyślne obsługują przypadek, gdy znasz parametry z góry. Czasem ich nie znasz: chcesz, żeby funkcja przyjmowała dowolną liczbę argumentów, albo przekazać zestaw argumentów do innej funkcji. Do tego służą ...rest i operator spread, o których w następnej części.
Najczęściej zadawane pytania
Jak ustawić domyślną wartość parametru w JavaScript?
W sygnaturze funkcji po nazwie parametru wstaw = i wartość domyślną: function greet(name = 'friend') { ... }. Jeśli wywołujący nie przekaże wartości (albo przekaże undefined), zostanie użyta wartość domyślna. To składnia ES6 i działa we wszystkich współczesnych środowiskach JavaScript.
Jaka jest różnica między parametrami a argumentami?
Parametry to nazwy w definicji funkcji: function add(a, b) ma parametry a i b. Argumenty to rzeczywiste wartości przekazywane przy wywołaniu: add(2, 3) przekazuje argumenty 2 i 3. To rozróżnienie przydaje się przy czytaniu komunikatów o błędach i dokumentacji.
Czy parametr domyślny działa, gdy przekażę null?
Nie. Wartości domyślne działają tylko wtedy, gdy argument to undefined (albo w ogóle go nie ma). Jawne przekazanie null oznacza "daję ci wartość i ta wartość to null", więc wartość domyślna jest pomijana. To zaskakuje osoby przychodzące z języków, w których null i undefined to to samo.
Czy wartość domyślna może korzystać z innego parametru?
Tak. Parametry są obliczane od lewej do prawej, więc wartość domyślna późniejszego parametru może używać wcześniejszych: function box(width, height = width). W wartości domyślnej możesz też wywoływać funkcje, na przykład function log(msg, time = Date.now()), a wyrażenie wykonuje się od nowa przy każdym wywołaniu.