Jaki jest najlepszy sposób na fałszywe przeciążenie funkcji w JavaScript?
Wiem, że nie jest możliwe przeciążenie funkcji w Javascript, tak jak w innych językach. Gdybym potrzebował funkcji z dwoma zastosowań foo(x)
i foo(x,y,z)
który jest najlepszy / preferowany sposób:
- Używanie przede wszystkim różnych nazw
- Używanie opcjonalnych argumentów, takich jak
y = y || 'default'
- Korzystanie z liczby argumentów
- Sprawdzanie typów argumentów
- Albo jak?
javascript
overloading
hamdiakoguz
źródło
źródło
Odpowiedzi:
Najlepszym sposobem na przeciążenie funkcji parametrami nie jest sprawdzenie długości argumentów ani typów; sprawdzanie typów po prostu spowolni kod i będziesz się dobrze bawić tablicami, zerami, obiektami itp.
Większość programistów robi sprzężenie z obiektem jako ostatnim argumentem swoich metod. Ten obiekt może pomieścić wszystko.
Następnie możesz obsłużyć go w dowolny sposób w metodzie. [Switch, if-else itp.]
źródło
if(opts['test']) //if test param exists, do something.. if(opts['bar']) //if bar param exists, do something
arguments.length
nie jest zalecane? Byłem tu już wcześniej i czytałem To, co robi większość programistów, to ... ale jestem pewien, że to jedyne miejsce, w którym to widziałem. Ta metoda psuje także składniową cukierkowość „przeciążeń”!Często to robię:
DO#:
Odpowiednik JavaScript:
Ten konkretny przykład jest w rzeczywistości bardziej elegancki w javascript niż C #. Parametry, które nie są określone, są „niezdefiniowane” w javascript, co w instrukcji if powoduje wyrażenie false. Jednak definicja funkcji nie przekazuje informacji, że p2 i p3 są opcjonalne. Jeśli potrzebujesz dużo przeciążenia, jQuery zdecydowało się użyć obiektu jako parametru, na przykład jQuery.ajax (opcje). Zgadzam się z nimi, że jest to najskuteczniejsze i najlepiej udokumentowane podejście do przeciążania, ale rzadko potrzebuję więcej niż jednego lub dwóch szybkich parametrów opcjonalnych.
EDYCJA: zmieniono test IF zgodnie z sugestią Iana
źródło
undefined
w JS, a nienull
. Najlepszą praktyką jest, aby nigdy niczego nie ustawiaćundefined
, więc nie powinno to stanowić problemu, o ile zmienisz test nap2 === undefined
.false
jako ostatni argument, nie będzie on konkatenowany"false"
do końca, ponieważif(p3)
nie rozgałęzi się.typeof p2 === "undefined"
prawdopodobnie jest to odwrotność tego, czego oczekujesz w przypadku twojego przykładu, myślę, żetypeof p2 !== "undefined"
to, co zamierzałeś. Ponadto, czy mogę zasugerować, że ma on łączyć łańcuch, liczbę i wartość logiczną, co faktycznie robiszp2 === "number"; p3 === "boolean"
===
i!==
? Dlaczego nie po prostu użyć==
i!=
?W JavaScript nie ma przeciążenia rzeczywistej funkcji, ponieważ pozwala ona na przekazanie dowolnej liczby parametrów dowolnego typu. Musisz sprawdzić wewnątrz funkcji, ile argumentów zostało przekazanych i jakiego typu są.
źródło
Prawidłowa odpowiedź brzmi: NIE JEST PRZEKŁADANIE W JAVASCRIPT.
Sprawdzanie / przełączanie wewnątrz funkcji nie jest PRZEGLĄDANIE.
Pojęcie przeciążenia: W niektórych językach programowania przeciążenie funkcji lub przeciążenie metody to możliwość tworzenia wielu metod o tej samej nazwie z różnymi implementacjami. Wywołania funkcji przeciążonej będą uruchamiać określoną implementację tej funkcji odpowiednią do kontekstu wywołania, umożliwiając jednemu wywołaniu funkcji wykonywanie różnych zadań w zależności od kontekstu.
Na przykład doTask () i doTask (obiekt O) są metodami przeciążonymi. Aby wywołać to drugie, obiekt musi zostać przekazany jako parametr, podczas gdy ten pierwszy nie wymaga parametru i jest wywoływany z pustym polem parametru. Częstym błędem byłoby przypisanie wartości domyślnej do obiektu w drugiej metodzie, co spowodowałoby dwuznaczny błąd wywołania, ponieważ kompilator nie wiedziałby, której z dwóch metod należy użyć.
https://en.wikipedia.org/wiki/Function_overloading
Wszystkie sugerowane implementacje są świetne, ale prawdę mówiąc, nie ma natywnej implementacji dla JavaScript.
źródło
Istnieją dwa sposoby, aby podejść do tego lepiej:
Przekaż słownik (tablicę asocjacyjną), jeśli chcesz pozostawić dużą elastyczność
Weź obiekt jako argument i użyj dziedziczenia opartego na prototypach, aby zwiększyć elastyczność.
źródło
Oto podejście, które pozwala na rzeczywiste przeciążenie metody przy użyciu typów parametrów, pokazane poniżej:
Edycja (2018) : Odkąd napisano to w 2011 r., Szybkość bezpośrednich wywołań metod znacznie wzrosła, podczas gdy prędkość przeciążonych metod nie.
Nie polecam takiego podejścia, ale warto zastanowić się nad tym, jak rozwiązać tego rodzaju problemy.
Oto punkt odniesienia dla różnych podejść - https://jsperf.com/function-overloading . To pokazuje, że funkcja przeciążenia (biorąc pod uwagę typy) może być około 13 razy wolniej w Google V8 Chrome jak z 16,0 (beta) .
Oprócz przekazywania obiektu (tj.
{x: 0, y: 0}
), Można również zastosować podejście C, gdy jest to właściwe, odpowiednio nazywając metody. Na przykład Vector.AddVector (wektor), Vector.AddIntegers (x, y, z, ...) i Vector.AddArray (integerArray). Możesz spojrzeć na biblioteki C, takie jak OpenGL, na inspirację nazewnictwa.Edit : Dodałem odniesienia do przekazywania obiektu i testowania dla obiektu przy użyciu zarówno
'param' in arg
aarg.hasOwnProperty('param')
, a funkcja przeciążenia jest znacznie szybsze niż przekazując obiekt oraz sprawdzenie właściwości (w tym teście co najmniej).Z perspektywy projektowej przeciążenie funkcji jest poprawne lub logiczne tylko wtedy, gdy przeciążone parametry odpowiadają tej samej akcji. Jest więc oczywiste, że powinna istnieć podstawowa metoda, która dotyczy tylko określonych szczegółów, w przeciwnym razie może to wskazywać na niewłaściwe wybory projektowe. Można więc również rozwiązać problem nadmiernego obciążenia funkcji, konwertując dane do odpowiedniego obiektu. Oczywiście należy wziąć pod uwagę zakres problemu, ponieważ nie ma potrzeby robienia skomplikowanych projektów, jeśli zamierzasz po prostu wydrukować nazwę, ale w przypadku projektowania ram i bibliotek taka myśl jest uzasadniona.
Mój przykład pochodzi z implementacji Rectangle - stąd wzmianka o Dimension i Point. Być może Rectangle mógłby dodać
GetRectangle()
metodę doDimension
iPoint
prototypu, a następnie problem z przeciążeniem funkcji zostanie rozwiązany. A co z prymitywami? Mamy długość argumentów, która jest teraz poprawnym testem, ponieważ obiekty mająGetRectangle()
metodę.źródło
Najlepszy sposób naprawdę zależy od funkcji i argumentów. Każda z opcji jest dobrym pomysłem w różnych sytuacjach. Zasadniczo próbuję je w następującej kolejności, dopóki jeden z nich nie zadziała:
Używanie opcjonalnych argumentów, takich jak y = y || 'domyślna'. Jest to wygodne, jeśli możesz to zrobić, ale nie zawsze może działać praktycznie, np. Gdy 0 / null / undefined byłoby poprawnym argumentem.
Korzystanie z liczby argumentów. Podobne do ostatniej opcji, ale może działać, gdy nr 1 nie działa.
Sprawdzanie typów argumentów. Może to działać w niektórych przypadkach, gdy liczba argumentów jest taka sama. Jeśli nie możesz w wiarygodny sposób określić typów, może być konieczne użycie różnych nazw.
Używanie przede wszystkim różnych nazw. Być może trzeba to zrobić, jeśli inne opcje nie będą działać, nie są praktyczne lub w celu zachowania spójności z innymi powiązanymi funkcjami.
źródło
Problem polega na tym, że JavaScript NIE obsługuje przeciążania metod. Tak więc, jeśli zobaczy / przeanalizuje dwie lub więcej funkcji o tych samych nazwach, po prostu weźmie pod uwagę ostatnią zdefiniowaną funkcję i zastąpi poprzednie.
Jeden ze sposobów, który moim zdaniem jest odpowiedni dla większości przypadków, jest następujący:
Powiedzmy, że masz metodę
Zamiast metody przeciążania, która nie jest możliwa w javascript , możesz zdefiniować nową metodę
a następnie zmodyfikuj pierwszą funkcję w następujący sposób -
Jeśli masz wiele takich przeciążonych metod, rozważ użycie więcej
switch
niż tylkoif-else
instrukcji.( więcej szczegółów )
PS: Powyższy link prowadzi do mojego osobistego bloga, który zawiera dodatkowe informacje.
źródło
Nie jestem pewien co do najlepszych praktyk, ale oto jak to zrobić:
źródło
Właśnie tego spróbowałem, może odpowiada Twoim potrzebom. W zależności od liczby argumentów można uzyskać dostęp do innej funkcji. Inicjujesz go przy pierwszym wywołaniu. A mapa funkcji jest ukryta w zamknięciu.
Sprawdź to.
źródło
Ponieważ JavaScript nie ma funkcji przeciążenia funkcji, zamiast tego można użyć obiektu. Jeśli wymagany jest jeden lub dwa argumenty, lepiej trzymać je oddzielnie od obiektu opcji. Oto przykład, jak użyć obiektu opcji i zapełnionych wartości do wartości domyślnej w przypadku, gdy wartość nie została przekazana w obiekcie opcji.
oto przykład użycia obiektu opcji
źródło
W javascript nie ma sposobu na przeciążenie funkcji. Dlatego polecam następujące
typeof()
metody zamiast wielu funkcji w celu fałszywego przeciążenia.Powodzenia!
źródło
var type = typeof param; if (type === 'string') ...
WPROWADZENIE
Jak dotąd przeczytanie tak wielu odpowiedzi sprawiłoby każdemu ból głowy. Każdy, kto próbuje poznać tę koncepcję, musi znać następujące warunki wstępne .
Function overloading Definition
,Function Length property
,Function argument property
Function overloading
w najprostszej formie oznacza, że funkcja wykonuje różne zadania na podstawie liczby przekazywanych jej argumentów. W szczególności TASK1, TASK2 i TASK3 są podświetlone poniżej i są wykonywane na podstawie liczbyarguments
przekazanych do tej samej funkcjifooYo
.UWAGA - JS nie zapewnia wbudowanej możliwości przeciążenia funkcji.
Alternatywny
John E Resig (twórca JS) wskazał alternatywę, która wykorzystuje powyższe warunki wstępne, aby osiągnąć zdolność do implementacji przeciążenia funkcji.
Poniższy kod wykorzystuje proste, ale naiwne podejście za pomocą
if-else
lubswitch
instrukcji.argument-length
właściwość.Inna technika jest znacznie bardziej czysta i dynamiczna. Najważniejszym punktem tej techniki jest
addMethod
funkcja ogólna.definiujemy funkcję,
addMethod
która służy do dodawania różnych funkcji do obiektu o tej samej nazwie, ale o różnych funkcjach .poniżej
addMethod
funkcja akceptuje nazwę obiektu trzech parametrów, nazwęobject
funkcjiname
i funkcję, którą chcemy wywołaćfn
.addMethod
Definicja wewnętrznavar old
przechowuje odniesienie do poprzedniego, którefunction
jest przechowywane za pomocą zamknięcia - bańki ochronnej.addMethod
dodaje trzy funkcje, które przy wywołaniu przy użyciuninja.whatever(x)
liczby argumentów,x
które mogą być dowolne, tj. albo puste, albo jedna lub więcej niż jedna, wywołuje różne funkcje określone podczas korzystania zaddMethod
funkcji.źródło
Innym sposobem podejścia do tego jest użycie specjalnej zmiennej: arguments , jest to implementacja:
dzięki czemu możesz zmodyfikować ten kod, aby:
źródło
Spójrz na to. To jest bardzo fajne. http://ejohn.org/blog/javascript-method-overloading/ Trick Javascript, aby umożliwić wykonywanie takich połączeń:
źródło
Func(new Point())
iFunc(new Rectangle())
będę wykonywać różne funkcje. Ale muszę zaznaczyć, że jest to brudny hack, ponieważ przeciążenie metody jest tak naprawdę zadaniem czasu kompilacji, a nie czasu wykonywania.Przeciążenie funkcji w JavaScript:
Przeciążenie funkcji to zdolność języka programowania do tworzenia wielu funkcji o tej samej nazwie z różnymi implementacjami. wywołanie funkcji przeciążonej spowoduje uruchomienie określonej implementacji tej funkcji, stosownie do kontekstu wywołania. Ten kontekst jest zwykle liczbą otrzymywanych argumentów i pozwala jednemu wywołaniu funkcji zachowywać się inaczej w zależności od kontekstu.
JavaScript nie ma wbudowanego przeciążenia funkcji. To zachowanie można jednak emulować na wiele sposobów. Oto wygodny prosty:
W scenariuszach, w których nie wiesz, ile argumentów otrzymasz, możesz użyć operatora reszty, który jest trzema kropkami
...
. Przekształci resztę argumentów w tablicę. Uważaj jednak na kompatybilność przeglądarki. Oto przykład:źródło
Ponieważ ten post zawiera już wiele różnych rozwiązań, pomyślałem, że opublikuję kolejne.
można tego użyć, jak pokazano poniżej:
To rozwiązanie nie jest idealne, ale chcę tylko pokazać, jak można to zrobić.
źródło
Możesz użyć „addMethod” z John Resig. Za pomocą tej metody można „przeciążać” metody na podstawie liczby argumentów.
Stworzyłem również alternatywę dla tej metody, która wykorzystuje buforowanie do przechowywania odmian funkcji. Różnice opisano tutaj
źródło
Forwarding Pattern => najlepsza praktyka w zakresie przeciążania JS
Przejdź do innej funkcji, której nazwa jest zbudowana z 3 i 4 punktu:
Zastosowanie w twojej sprawie:
Inna złożona próbka:
źródło
Przeciążenie funkcji przez dynamiczny polimorfizm w 100 liniach JS
Jest to z większego ciała kodu, który obejmuje
isFn
,isArr
itd funkcji Kontrola typów. Poniższa wersja VanillaJS została przerobiona w celu usunięcia wszystkich zewnętrznych zależności, jednak będziesz musiał zdefiniować własne funkcje sprawdzania typu do użycia w.add()
wywołaniach.Uwaga: Jest to funkcja samowykonująca się (dzięki czemu możemy mieć zakres zamknięcia / zamknięcia), stąd przypisanie do
window.overload
zamiastfunction overload() {...}
.Stosowanie:
Program wywołujący określa ich przeciążone funkcje, przypisując zmienną do zwracanej wartości
overload()
. Dzięki łączeniu dodatkowe przeciążenia można zdefiniować szeregowo:Pojedynczy opcjonalny argument
overload()
definiujący funkcję „domyślną”, która ma być wywoływana, jeśli podpis nie może zostać zidentyfikowany. Argumenty do.add()
:fn
:function
określenie przeciążenia;a_vArgumentTests
:Array
zfunction
s definiuje testy do uruchomienia naarguments
. Każdyfunction
akceptuje pojedynczy argument i zwracatrue
twój na podstawie tego, czy argument jest poprawny;sAlias
(Opcjonalnie):string
zdefiniowanie aliasu w celu uzyskania bezpośredniego dostępu do funkcji przeciążenia (fn
), np.myOverloadedFn.noArgs()
Wywoła tę funkcję bezpośrednio, unikając dynamicznych testów polimorfizmu argumentów.Ta implementacja faktycznie pozwala na więcej niż tylko tradycyjne przeciążenie funkcji, ponieważ drugi
a_vArgumentTests
argument.add()
w praktyce definiuje typy niestandardowe. Możesz więc przekazywać argumenty nie tylko na podstawie typu, ale także na zakresach, wartościach lub kolekcjach wartości!Jeśli przejrzysz 145 linii kodu
overload()
, zobaczysz, że każdy podpis jest podzielony na kategorie według liczbyarguments
przekazanych do niego znaków. Robimy to, aby ograniczyć liczbę uruchomionych testów. Śledzę również liczbę połączeń. Przy pewnym dodatkowym kodzie tablice przeciążonych funkcji mogą zostać ponownie posortowane, aby najpierw przetestować częściej nazywane funkcje, ponownie dodając pewną miarę zwiększenia wydajności.Teraz są pewne zastrzeżenia ... Ponieważ Javascript jest luźno wpisany, będziesz musiał uważać na swój,
vArgumentTests
ponieważinteger
można go zweryfikować jakofloat
itp.Wersja JSCompress.com (1114 bajtów, 744 bajty skompresowane g):
źródło
Możesz teraz przeciążać funkcje w ECMAScript 2018 bez wypełnień, sprawdzać długość / typ zmiennej itp., Wystarczy użyć składni rozkładania .
Co to jest składnia rozprzestrzeniania?
Uwaga: składnia rozproszona w literałach obiektowych nie działa w Edge i IE i jest funkcją eksperymentalną. zobacz kompatybilność przeglądarki
źródło
Coś takiego można zrobić w przypadku przeciążenia funkcji.
Źródło
źródło
To stare pytanie, ale myślę, że potrzebuje kolejnego wpisu (choć wątpię, by ktokolwiek go przeczytał). Użycie wyrażeń funkcji natychmiast wywołanych (IIFE) może być używane w połączeniu z zamknięciami i funkcjami wbudowanymi, aby umożliwić przeciążenie funkcji. Rozważ następujący (wymyślony) przykład:
Krótko mówiąc, użycie IIFE tworzy zasięg lokalny, co pozwala nam zdefiniować zmienną prywatną
old
do przechowywania odniesienia do początkowej definicji funkcjifoo
. Ta funkcja zwraca następnie funkcję wbudowaną,newFoo
która rejestruje zawartość obu dwóch argumentów, jeśli zostaną przekazane dokładnie dwa argumentya
ib
lub wywołujeold
funkcję ifarguments.length !== 2
. Ten wzorzec można powtarzać dowolną liczbę razy, aby wyposażyć jedną zmienną w kilka różnych definicji funkcjonalnych.źródło
Chciałbym podzielić się przydatnym przykładem podejścia podobnego do przeciążonego.
Użycie: Clear (); // Usuwa cały dokument
Wyczyść (myDiv); // Czyści panel, do którego odwołuje się myDiv
źródło
JavaScript jest językiem bez typów i myślę, że sensowne jest przeciążenie metody / funkcji w odniesieniu do liczby parametrów. Dlatego zalecałbym sprawdzenie, czy parametr został zdefiniowany:
źródło
Od lipca 2017 r. Następującą techniką jest wspólna technika. Pamiętaj, że możemy również sprawdzać typ w ramach funkcji.
źródło
Dla twojego przypadku użycia, tak bym sobie z tym poradził
ES6
(ponieważ jest to już koniec 2017 roku):Możesz oczywiście dostosować to do pracy z dowolną ilością parametrów i po prostu odpowiednio zmienić instrukcje warunkowe.
źródło
w JS nie ma faktycznego przeciążenia, w każdym razie nadal możemy symulować przeciążenie metody na kilka sposobów:
metoda nr 1: użyj obiektu
metoda nr 2: użyj parametrów rest (spread)
metoda nr 3: użyj niezdefiniowanego
metoda nr 4: sprawdzanie typu
źródło
Chociaż parametry domyślne nie są przeciążone, może rozwiązać niektóre problemy, z którymi spotykają się programiści w tym obszarze. Dane wejściowe są ściśle określone przez zamówienie, nie można ponownie zamówić, jak chcesz, jak w klasycznym przeciążeniu:
Wyniki w (za rok 2020):
Więcej informacji: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters
źródło
Pierwsza opcja naprawdę zasługuje na uwagę, ponieważ wymyśliłem ją w dość złożonej konfiguracji kodu. Tak więc moja odpowiedź brzmi
Z małą, ale niezbędną wskazówką, nazwy powinny wyglądać inaczej dla komputera, ale nie dla ciebie. Nazwa przeciążonych funkcji, takich jak: func, func1, func2.
źródło