Читать книгу JavaScript funkcyjnie. Zrównoważone, pragmatyczne programowanie funkcyjne w JavaScript - Kyle Simpson - Страница 25

Zliczanie wejść

Оглавление

Liczba argumentów funkcji oznacza „oczekiwanie”, ile argumentów powinniśmy do niej przekazać. Jest ona określona przez liczbę parametrów, które zostały zadeklarowane:

function foo(x,y,z) {

// ..

}

foo(..) oczekuje trzech argumentów, gdyż ma trzy zadeklarowane parametry. Ten licznik nosi określoną nazwę: argumentowość. Jest to liczba parametrów w deklaracji funkcji. Argumentowość foo(..) wynosi 3.

Ponadto funkcja o argumentowości 1 nazywana jest „jednoargumentową”, funkcja o argumentowości 2 jest „dwuargumentowa”, a funkcja o argumentowości 3 lub więcej – „wieloargumentowa”.

Możemy chcieć sprawdzić odwołanie do funkcji podczas wykonania, aby określić jej argumentowość. Można to zrobić za pomocą własności length w odwołaniu do tej funkcji:

function foo(x,y,z) {

// ..

}

foo.length; // 3

Jednym z powodów określania argumentowości podczas wykonywania jest sprawdzenie, czy kawałek kodu otrzymał odwołanie do funkcji z wielu źródeł i wysłał różne wartości zależnie od argumentowości każdej z nich.

Na przykład wyobraźmy sobie przypadek, gdzie odwołanie do funkcji fn może oczekiwać jednego, dwóch lub trzech argumentów, ale na ostatniej pozycji zawsze chcemy przekazać zmienną x:

// `fn` jest ustawione na odwołanie do jakiejś funkcji

// `x` Ma jakąś wartość

if (fn.length == 1) {

fn( x );

}

else if (fn.length == 2) {

fn( undefined, x );

}

else if (fn.length == 3) {

fn( undefined, undefined, x );

}


Wskazówka

Własność length funkcji jest tylko do odczytu i zostaje określona w momencie definicji funkcji. Należy ją traktować jako istotny element metadanych, opisujący coś związanego z przewidywanym wykorzystaniem funkcji.

Trzeba mieć świadomość, że są konkretne odmiany list parametrów, które sprawiają, że własność length funkcji informuje o czymś innym, niż można by oczekiwać:

function foo(x,y = 2) {

// ..

}

function bar(x,...args) {

// ..

}

function baz( {a,b} ) {

// ..

}

foo.length; // 1

bar.length; // 1

baz.length; // 1

A co ze zliczaniem liczby argumentów otrzymanych w aktualnym wywołaniu funkcji? Tu mamy sytuację, która kiedyś była trywialna, ale teraz będzie nieco bardziej skomplikowana. Każda funkcja ma dostępny obiekt arguments (podobny do tablicy), który przechowuje odwołania do każdego przekazanego argumentu. Możemy więc sprawdzić własność length dla arguments, aby określić, ile zostało w rzeczywistości przekazanych:

function foo(x,y,z) {

console.log( arguments.length );

}

foo( 3, 4 ); // 2

Od wersji ES5 (a konkretnie trybu ścisłego), arguments jest przez niektórych uważane za przestarzałe. Wielu unika stosowania go, o ile jest to możliwe. W JS „nigdy” nie usuwamy kompatybilności wstecznej, niezależnie od tego, w jakim stopniu to może pomóc w przyszłym rozwoju, więc arguments nigdy nie zostanie usunięte. Ale obecnie często zaleca się, aby unikać go, gdy tylko jest to możliwe.

Sugeruję jednak, że arguments.length, i tylko ono, może być stosowane w przypadkach, gdy musimy uważać na liczbę przekazywanych argumentów. W przyszłej wersji JS może ewentualnie zostanie dodana własność, która zaoferuje możliwość określenia liczby przekazanych argumentów, bez konsultacji z arguments.length. Jeśli tak się stanie, to będziemy mogli całkiem porzucić arguments!

Ostrożnie: nigdy nie należy uzyskiwać dostępu do argumentów według pozycji, jak arguments[1]. Trzymajmy się jedynie arguments.length i tylko wtedy, gdy musimy to robić.

Poza tym jak uzyskamy dostęp do argumentu, który został przekazany na pozycji poza liczbą zadeklarowanych parametrów? Odpowiem na to za chwilę: ale najpierw musimy cofnąć się o krok i zapytać się: „Dlaczego mogę chcieć to zrobić?”. Poważnie. Pomyślcie o tym uważnie przez minutę.

To zdarza się dość rzadko. Nie powinno to być coś, czego zwykle oczekujemy lub na czym się opieramy przy pisaniu naszych funkcji. Jeśli okaże się, że mamy taki scenariusz, spędźmy dodatkowych 20 minut, próbując zaprojektować interakcje z funkcją w inny sposób. Nazwijmy ten dodatkowy argument, nawet jeśli jest to sytuacja wyjątkowa.

Sygnaturę funkcji, która akceptuje nieokreśloną liczbę argumentów, określa się jako funkcję ze zmienną liczbą argumentów. Niektórzy wolą ten rodzaj funkcji, ale moim zdaniem większość programistów FP unika tego, jeśli to możliwe.

OK, na razie wystarczy.

Powiedzmy, że chcemy mieć dostęp do argumentów w sposób pozycyjny, podobny do tablicy, zapewne dlatego, że chcemy mieć dostęp do argumentu, który nie ma dla swojej pozycji formalnego parametru. Jak możemy to zrobić?

Na pomoc przychodzi ES6! Zadeklarujmy naszą funkcję za pomocą operatora ... – określanego różnie, jako „rozprowadzający” (spread), „spoczynkowy” (rest) lub (co ja preferuję) „zbierający” (gather):

function foo(x,y,z,...args) {

// ..

}

Czy widzicie na liście parametrów...args? To deklaratywna postać w ES6, która mówi silnikowi, aby odebrał (hmm, „zebrał”) wszystkie pozostałe argumenty (jeśli są), które nie są przypisane do nazwanych parametrów, a następnie umieścił je w jawnej tablicy o nazwie args. args będzie zawsze tablicą, nawet jeśli jest ona pusta. Ale nie będzie zawierać wartości przypisanych do parametrów x, y i z, tylko to, co zostanie przekazane poza tymi trzema pierwszymi wartościami:

function foo(x,y,z,...args) {

console.log( x, y, z, args );

}

foo(); // niezdefiniowane niezdefiniowane niezdefiniowane []

foo( 1, 2, 3 ); // 1 2 3 []

foo( 1, 2, 3, 4 ); // 1 2 3 [ 4 ]

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

Tak więc, jeśli naprawdę chcemy zaprojektować funkcję, która może przyjmować dowolną liczbę przekazywanych argumentów, używamy na końcu ...args (lub innej wybranej nazwy). Mamy teraz prawdziwą, nieprzestarzałą, przyjemną tablicę, z której mamy dostęp do wartości tych argumentów.

Należy zwrócić uwagę na fakt, że wartość 4 jest na pozycji 0 tablicy args, a nie na pozycji 3. Natomiast wartość length nie będzie zawierać tych trzech wartości 1, 2 i 3. ...args zbiera wszystko inne, nie obejmując x, y i z.

Możemy użyć operatora ... na liście parametrów, nawet gdy nie ma zadeklarowanych innych formalnych parametrów:

function foo(...args) {

// ..

}

Teraz args będzie pełną tablicą argumentów, niezależnie od tego, czym one są, a my możemy użyć args.length do określenia, ile dokładnie argumentów zostało przekazanych. I jeśli mamy na to ochotę, możemy bezpiecznie używać args[1] lub args[317]. Ale proszę, nie przekazujcie 318 argumentów.

JavaScript funkcyjnie. Zrównoważone, pragmatyczne programowanie funkcyjne w JavaScript

Подняться наверх