Tworząc funkcję JavaScript z wieloma argumentami, zawsze mam do czynienia z takim wyborem: przekazać listę argumentów vs. przekazać obiekt opcji.
Na przykład piszę funkcję do mapowania nodeList do tablicy:
function map(nodeList, callback, thisObject, fromIndex, toIndex){
...
}
Zamiast tego mógłbym użyć tego:
function map(options){
...
}
gdzie opcje to obiekt:
options={
nodeList:...,
callback:...,
thisObject:...,
fromIndex:...,
toIndex:...
}
Który z nich jest zalecany? Czy istnieją wytyczne dotyczące tego, kiedy używać jednej, a kiedy drugiej?
[Aktualizacja] Wydaje się, że istnieje konsensus na rzecz obiektu opcji, więc chciałbym dodać komentarz: jednym z powodów, dla których kusiło mnie, aby użyć listy argumentów w moim przypadku, było zachowanie zgodne z JavaScriptem wbudowana metoda array.map.
Array.prototype.map
ma proste API, które nie powinno sprawiać kłopotów żadnego częściowo doświadczonego programisty.Odpowiedzi:
Podobnie jak wiele innych, często wolę przekazywać funkcję
options object
do funkcji zamiast przekazywać długą listę parametrów, ale tak naprawdę zależy to od dokładnego kontekstu.Używam czytelności kodu jako papierka lakmusowego.
Na przykład, jeśli mam to wywołanie funkcji:
Myślę, że kod jest całkiem czytelny tak, jak jest, a przekazywanie poszczególnych parametrów jest w porządku.
Z drugiej strony istnieją funkcje z takimi wywołaniami:
Całkowicie nieczytelne, chyba że zrobisz jakieś badania. Z drugiej strony ten kod dobrze się czyta:
To bardziej sztuka niż nauka, ale gdybym miał nazwać praktyczne zasady:
Użyj parametru opcji, jeśli:
źródło
Wiele argumentów dotyczy głównie parametrów obowiązkowych. Nie ma z nimi nic złego.
Jeśli masz opcjonalne parametry, sprawa się komplikuje. Jeśli jeden z nich polega na innych, tak że mają określoną kolejność (np. Czwarty potrzebuje trzeciego), nadal powinieneś używać wielu argumentów. Prawie wszystkie natywne metody EcmaScript i DOM działają w ten sposób. Dobrym przykładem jest
open
metoda XMLHTTPrequests , w której ostatnie 3 argumenty są opcjonalne - reguła jest taka jak „bez hasła bez użytkownika” (zobacz także dokumentację MDN ).Obiekty opcji są przydatne w dwóch przypadkach:
undefined
.W twoim przypadku polecam
map(nodeList, callback, options)
.nodelist
icallback
są wymagane, pozostałe trzy argumenty pojawiają się tylko sporadycznie i mają rozsądne wartości domyślne.Innym przykładem jest
JSON.stringify
. Możesz chcieć użyćspace
parametru bez przekazywaniareplacer
funkcji - wtedy musisz wywołać…, null, 4)
. Obiekt arguments mógłby być lepszy, chociaż nie jest tak naprawdę rozsądny dla tylko 2 parametrów.źródło
Najlepszym rozwiązaniem będzie wykorzystanie podejścia „opcji jako obiektu”. Nie musisz martwić się o kolejność właściwości i jest większa elastyczność w przekazywaniu danych (na przykład parametry opcjonalne)
Utworzenie obiektu oznacza również, że opcje mogą być łatwo używane w wielu funkcjach:
źródło
Myślę, że jeśli tworzysz instancję lub wywołujesz metodę obiektu, chcesz użyć obiektu opcji. Jeśli jest to funkcja, która operuje tylko jednym lub dwoma parametrami i zwraca wartość, preferowana jest lista argumentów.
W niektórych przypadkach dobrze jest używać obu. Jeśli twoja funkcja ma jeden lub dwa wymagane parametry i kilka opcjonalnych, ustaw pierwsze dwa parametry jako wymagane, a trzeci jako opcjonalny skrót opcji.
Na twoim przykładzie zrobiłbym to
map(nodeList, callback, options)
. Lista węzłów i wywołanie zwrotne są wymagane, dość łatwo jest stwierdzić, co się dzieje, po prostu odczytując wywołanie do niego i przypomina to istniejące funkcje mapy. Wszelkie inne opcje można przekazać jako opcjonalny trzeci parametr.źródło
Twój komentarz do pytania:
Więc dlaczego tego nie zrobić? (Uwaga: to jest dość surowy JavaScript. Zwykle używałbym
default
skrótu i zaktualizowałbym go opcjami przekazanymi za pomocą Object.extend lub JQuery.extend lub podobnych ...)Tak więc, ponieważ teraz jest o wiele bardziej oczywiste, co jest opcjonalne, a co nie, wszystkie z nich są prawidłowymi zastosowaniami funkcji:
źródło
Mogę się trochę spóźnić na imprezę z tą odpowiedzią, ale szukałem opinii innych programistów na ten temat i trafiłem na ten wątek.
Zdecydowanie nie zgadzam się z większością respondentów i opowiadam się za podejściem „wielu argumentów”. Moim głównym argumentem jest to, że zniechęca to innych anty-wzorców, takich jak „mutowanie i zwracanie obiektu param” lub „przekazywanie tego samego obiektu param innym funkcjom”. Pracowałem w bazach kodu, które w znacznym stopniu nadużywały tego anty-wzorca, a debugowanie kodu, który to robi, szybko staje się niemożliwe. Myślę, że jest to bardzo praktyczna reguła specyficzna dla JavaScript, ponieważ Javascript nie jest silnie wpisany na maszynie i pozwala na takie dowolnie zbudowane obiekty.
Osobiście uważam, że programiści powinni być jawni podczas wywoływania funkcji, unikać przekazywania nadmiarowych danych i unikać modyfikacji przez odniesienie. Nie chodzi o to, że ten wzorzec wyklucza pisanie zwięzłego, poprawnego kodu. Po prostu czuję, że dzięki temu twój projekt znacznie łatwiej wpadnie w złe praktyki programistyczne.
Rozważ następujący okropny kod:
Tego rodzaju nie tylko wymaga bardziej przejrzystej dokumentacji, aby określić zamiar, ale także pozostawia miejsce na niejasne błędy. Co zrobić, jeśli modyfikuje developer
param1
wbar()
? Jak myślisz, ile czasu zajmie przeglądanie bazy kodów o wystarczającej wielkości, aby to złapać? Trzeba przyznać, że ten przykład jest nieco nieszczery, ponieważ zakłada, że programiści już popełnili kilka anty-wzorców do tego momentu. Pokazuje jednak, jak przepuszczanie obiektów zawierających parametry stwarza większe pole do popełniania błędów i niejednoznaczności, wymagając większej sumienności i przestrzegania stałej poprawności.Tylko moje dwa centy w tej sprawie!
źródło
To zależy.
Opierając się na moich obserwacjach dotyczących projektowania tych popularnych bibliotek, oto scenariusze, w których powinniśmy użyć obiektu opcji:
I scenariusze użycia listy parametrów:
źródło
Object jest bardziej preferowany, ponieważ jeśli przekazujesz obiekt, łatwo jest rozszerzyć liczbę właściwości w tych obiektach i nie musisz zwracać uwagi na kolejność, w jakiej argumenty zostały przekazane.
źródło
W przypadku funkcji, która zwykle używa wstępnie zdefiniowanych argumentów, lepiej użyć obiektu opcji. Odwrotnym przykładem będzie funkcja, która pobiera nieskończoną liczbę argumentów, na przykład: setCSS ({wysokość: 100}, {szerokość: 200}, {background: "# 000"}).
źródło
Przyjrzałbym się dużym projektom javascript.
Rzeczy takie jak mapa google często stwierdzają, że tworzone obiekty wymagają obiektu, ale funkcje wymagają parametrów. Myślę, że ma to związek z argumentami OPCJI.
Jeśli potrzebujesz argumentów domyślnych lub opcjonalnych, obiekt prawdopodobnie byłby lepszy, ponieważ jest bardziej elastyczny. Ale jeśli nie masz normalnych funkcjonalnych argumentów, są bardziej wyraźne.
Javascript też ma
arguments
obiekt. https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/argumentsźródło