Parametry funkcji

Pomijanie parametrów

W JavaScript nie ma obowiązku przesyłania wszystkich parametrów do funkcji.

function add(a, b) {
  return a + b;
}

console.log(add(40)); // NaN
1
2
3
4
5

Możemy wywołać funkcję add tylko z jednym parametrem. Oczywiście w takim przypadku nie należy spodziewać się, że funkcja tak wywoływana będzie działała poprawnie. Gdy ta funkcja zostaje wywołana z jednym parametrem, parametr b przyjmuje wartość undefined tak jakby był niezainicjalizowaną zmienną.

Ostatecznie więc następuje próba dodania liczby do undefined co kończy się wynikiem NaN.

Parametr domyślny dawniej

Zanim pojawiła się możliwość ustawiania parametrów domyślnych dla funkcji, używano prostego wzorca:

function add1(a, b) {
  a = a || 40;
  b = b || 2;
  return a + b;
}

console.log(add1(40)); // 42
1
2
3
4
5
6
7

Za pomocą operatora OR sprawdzano, czy parament istnieje i jeżeli nie, to przypisywano mu domyślną wartość. W tym przykładzie, jeżeli nie zostanie przekazany parametr a zostanie przypisana wartość 40. Jeżeli parametr b nie istnieje to zostanie mu przypisana wartość 2.

Taką funkcję można wywołać bez parametru:

console.log(add1()); // 42
console.log(add1(undefined, 2)); // 42
1
2

Można też wywołać ją z pominięciem pierwszego parametru stosując wartość undefined.

Ten wzorzec z domyślnymi parametrami ma jednak pewien problem:

console.log(add1(0, 0)); // 42
1

Wywołanie funkcji z parametrem 0 i tak powoduje użycie domyślnych wartości dla parametrów funkcji. Dzieje się tak, ponieważ operator OR sprawdza wartości fałszywe, a zero jest wartością fałszywą. W takim wypadku dostajemy nieprawidłowe wyniki.

Sprawdzanie, czy parametr jest undefined

Można sobie poradzić z tym problemem, stosując taki zapis:

function add2(a, b) {
  a = a === undefined ? 40 : a;
  b = b === undefined ? 2 : b;
  return a + b;
}

console.log(add2(0, 0)); // 0
console.log(add2(undefined, 0)); // 40
1
2
3
4
5
6
7
8

Możemy dokładnie sprawdzić, czy parametr ma wartość undefined co oznacza, że nie został przekazany. To rozwiązuje nam większość problemów z wartościami fałszywymi.

Przekazanie parametru null powiedzie się:

console.log(add2(40, null)); // 40
1

W tym przypadku wywołanie funkcji z null nie spowoduje przypisania parametru domyślnego. Ponieważ w funkcji dokładnie sprawdzamy, czy przesyłane parametry nie są undefined. Dlatego wartość null przechodzi dalej i niejawnie konwertowana jest na liczbę 0, dlatego przy dodawaniu mamy prawidłowe wyniki.

Możemy użyć jeszcze nowszego rozwiązania ES 2020:

function add3(a, b) {
  a = a ?? 40;
  b = b ?? 2;
  return a + b;
}

console.log(add3(null, undefined)); // 42
1
2
3
4
5
6
7

Z nullish operator możemy dokładnie sprawdzić wartości nullowe, czyli null i undefined. Jak widzicie, jest tutaj kilka rozwiązań tego problemu. W ES6 wprowadzono natomiast natywne parametry domyślne, które także możemy użyć.

Parametry domyślne ES6

W specyfikacji ES6 wprowadzono parametry domyślne, które możemy definiować zaraz przy parametrach funkcji:

function add4(a = 40, b = 2) {
  return a + b;
}

console.log(add4()); // 42
console.log(add4(undefined, 8)); // 48
console.log(add4(null, null)); // 0
console.log(add4(40, null)); // 40
console.log(add4(40)); // 42
console.log(add4(0, 0)); // 0
1
2
3
4
5
6
7
8
9
10

Od razu do parametrów funkcji możemy przypisać wartości, tak jak tutaj do parametrów a i b. Wartości te zostaną użyte, gdy parametr nie zostanie przekazany lub przekażemy wartość undefined.

Podobnie jak przy wcześniejszym rozwiązaniu, parametry funkcji są sprawdzane pod względem undefined, a nie wartości fałszywych. Dlatego możemy tam przekazywać wartości null, które konwertowane są do wartości 0, czy też wartości 0, które nie są tym razem traktowane jako wartości fałszywe. Mamy tutaj zdecydowanie mniej niespodzianek.

Parametry jako funkcja

Parametrem domyślnym funkcji mogą być też wyrażenia:

function world() {
  return 'World';
}

function hello(a, b = world()) {
  console.log(a + ' ' + b);
}

hello('Hello'); // 'Hello World'

hello('Hello', 'JS'); // 'Hello JS'
1
2
3
4
5
6
7
8
9
10
11

W tym przykładzie mamy zdefiniowaną funkcję world, która zwraca wartość string. Mamy też zdefiniowaną funkcję hello, która przyjmuje dwa parametry.

Jeżeli drugi parametr nie będzie przekazany to zostanie wywołana funkcja world, która zwróci wartość do drugiego parametru.

Jeżeli przekażemy obydwa parametry to funkcja world nie zostanie wywołana. Nie należy więc martwić się wydajnością tego rozwiązania i ewentualnym niepotrzebnym wywoływaniem funkcji. Funkcja jako parametr domyślny zostanie wywołana tylko w przypadku braku przekazania parametru.

Co warto zapamiętać

  • JavaScript nie wymusza na nas przekazania wszystkich parametrów do funkcji
  • możemy stosować własną implementację domyślnych parametrów, należy jednak uważać na przypadki brzegowe
  • w ES6 pojawiły się natywne parametry domyślne
  • parametrami domyślnymi mogą być też funkcje i wyrażenia