Powiedziano mi dzisiaj, że można wywołać funkcję bez nawiasów. Jedynym sposobem, w jaki mogłem wymyślić, było użycie funkcji takich jak apply
lubcall
.
f.apply(this);
f.call(this);
Ale wymagają one nawiasów apply
i call
pozostawienia nas na pierwszym miejscu. Rozważałem także pomysł przekazania funkcji do jakiegoś modułu obsługi zdarzeń, takiego jak setTimeout
:
setTimeout(f, 500);
Ale wtedy pojawia się pytanie „jak wywołujesz setTimeout
bez nawiasów?”
Więc jakie jest rozwiązanie tej zagadki? Jak można wywołać funkcję w JavaScript bez użycia nawiasów?
javascript
Mike Cluck
źródło
źródło
<insert any solution>
jest on obiektywnie lepszy lub bardziej przydatny niżf()
.Odpowiedzi:
Istnieje kilka różnych sposobów wywoływania funkcji bez nawiasów.
Załóżmy, że masz zdefiniowaną tę funkcję:
Następnie skorzystaj z kilku sposobów dzwonienia
greet
bez nawiasów:1. Jako konstruktor
Za pomocą
new
możesz wywołać funkcję bez nawiasów:Z MDN na
new
operatorze :2. Jako
toString
lubvalueOf
wdrożenietoString
ivalueOf
są metodami specjalnymi: są wywoływane niejawnie, gdy konieczna jest konwersja:Możesz (ab) użyć tego wzorca do wywołania
greet
bez nawiasów:Lub z
valueOf
:valueOf
itoString
są w rzeczywistości wywoływane z metody @@ na prymitywną (od ES6), więc można również zaimplementować tę metodę:2.b Przesłanianie
valueOf
w prototypie funkcjiMożesz wziąć poprzedni pomysł, aby zastąpić
valueOf
metodę naFunction
prototypie :Gdy to zrobisz, możesz napisać:
I chociaż w linii znajdują się nawiasy, faktyczne wywołanie wyzwalające nie ma nawiasów. Więcej informacji na ten temat można znaleźć na blogu „Metody wywoływania w JavaScript bez konieczności wywoływania ich”
3. Jako generator
Możesz zdefiniować funkcję generatora (z
*
), która zwraca iterator . Możesz to nazwać używając składni spreadu lubfor...of
składnią.Najpierw potrzebujemy wariantu generatora oryginalnej
greet
funkcji:Następnie nazywamy to bez nawiasów, definiując metodę iteratora @@ :
Zwykle generatory mają
yield
gdzieś słowo kluczowe, ale funkcja nie musi być wywoływana.Ostatnia instrukcja wywołuje funkcję, ale można to również zrobić za pomocą destrukcji :
lub
for ... of
konstrukcja, ale ma własne nawiasy:Pamiętaj, że możesz to zrobić również z oryginalną
greet
funkcją, ale spowoduje to wyjątek w tym procesie, pogreet
jej wykonaniu (przetestowane na FF i Chrome). Możesz zarządzać wyjątkiem za pomocątry...catch
bloku.4. Jako Getter
@ jehna1 ma na to pełną odpowiedź, więc daj mu kredyt. Oto sposób na wywołanie funkcji bez nawiasów w zakresie globalnym, unikając przestarzałej
__defineGetter__
metody.Object.defineProperty
Zamiast tego używa .W tym celu musimy stworzyć wariant oryginalnej
greet
funkcji:I wtedy:
Zamień na
window
dowolny obiekt globalny.Możesz wywołać oryginalną
greet
funkcję bez pozostawiania śladu na obiekcie globalnym w następujący sposób:Można jednak argumentować, że mamy tutaj nawiasy (chociaż nie są one zaangażowane w faktyczne wywołanie).
5. Jako funkcja znacznika
Od wersji ES6 można wywołać funkcję przekazującą jej dosłowność szablonu za pomocą następującej składni:
Zobacz „Oznaczone literały szablonów” .
6. Jako osoba obsługująca proxy
Od wersji ES6 możesz zdefiniować serwer proxy :
A następnie odczyt dowolnej wartości właściwości wywoła
greet
:Istnieje wiele odmian tego. Jeszcze jeden przykład:
7. Jako kontroler instancji
instanceof
Operator wykonuje@@hasInstance
sposób w drugim argumencie, gdy określona:źródło
valueOf
.func``;
'1' |> alert
Najłatwiej to zrobić z
new
operatorem:Jest to niekonwencjonalne i nienaturalne, ale działa i jest całkowicie legalne.
new
Operator nie wymaga nawiasów jeśli nie stosuje się parametry.źródło
!f
daje to samo, bez tworzenia instancji funkcji konstruktora (co wymaga utworzenia nowego tego kontekstu). Jest znacznie wydajniejszy i jest wykorzystywany w wielu popularnych bibliotekach (takich jak Bootstrap).+
,-
,~
) w takich bibliotek jest zapisać bajt w zminimalizowanej wersji biblioteki, gdzie wartość powrotna nie jest potrzebne. (tj.!function(){}()
) Zwykłą składnią samo-wywołującą jest(function(){})()
(niestetyfunction(){}()
nie jest to przeglądarka internetowa) Ponieważ najwyższa funkcja samo-wywoływania zwykle nie ma nic do zwrócenia, zwykle jest to cel tej techniki zapisywania bajtówfunction foo() { alert("Foo!") };
Na przykład:!foo
zwracafalse
Możesz używać pobierających i ustawiających.
Uruchom ten skrypt tylko z:
Edytować:
Możemy nawet argumentować!
Edycja 2:
Możesz także zdefiniować funkcje globalne, które można uruchomić bez nawiasów:
I z argumentami:
Zrzeczenie się:
Jak stwierdził @MonkeyZeus: Nigdy nie wolno używać tego fragmentu kodu w produkcji, bez względu na to, jak dobre są twoje intencje.
źródło
__defineGetter__
jest przestarzała. UżyjObject.defineProperty
zamiast tego.Oto przykład konkretnej sytuacji:
Chociaż to stwierdzenie w rzeczywistości nie wywołuje, ale prowadzi do przyszłego wywołania .
Ale wydaje mi się, że szare obszary mogą być odpowiednie dla takich zagadek :)
źródło
Jeśli zaakceptujemy podejście oparte na myśleniu bocznym, w przeglądarce istnieje kilka interfejsów API, których możemy użyć do wykonania dowolnego kodu JavaScript, w tym wywołania funkcji, bez żadnych znaków w nawiasach.
1.
location
ijavascript:
protokół:Jedną z takich technik jest nadużywanie
javascript:
protokołu przylocation
przydzielaniu.Przykład roboczy:
Chociaż technicznie
\x28
i\x29
nadal są w nawiasach po ocenie kodu, rzeczywisty(
i)
znak nie pojawiają się. Nawiasy są zamykane za pomocą ciągu JavaScript, który jest oceniany przy przypisaniu.2.
onerror
ieval
:Podobnie, w zależności od przeglądarki, możemy nadużywać globalnego
onerror
, ustawiając goeval
i rzucając czymś, co skreśli poprawny JavaScript. Ten jest trudniejszy, ponieważ przeglądarki są niespójne w tym zachowaniu, ale oto przykład dla Chrome.Przykład roboczy dla Chrome (nie Firefox, inne niesprawdzone):
Działa to w Chrome, ponieważ
throw'test'
przejdzie'Uncaught test'
jako pierwszy argumentonerror
, który jest prawie prawidłowym JavaScript. Jeśli zamiast tego zrobimy,throw';test'
to minie'Uncaught ;test'
. Teraz mamy prawidłowy JavaScript! Po prostu zdefiniujUncaught
i zamień test na ładowność.Podsumowując:
Taki kod jest naprawdę okropny i nigdy nie powinien być używany , ale czasami jest wykorzystywany w atakach XSS, więc morał tej historii nie polega na filtrowaniu nawiasów, aby zapobiec XSS. Dobrym pomysłem byłoby również użycie CSP w celu zapobiegania takiemu kodowi.
źródło
eval
i pisanie łańcucha bez użycia znaków w nawiasach.eval
zwykle wymaga nawiasów, stąd hackowanie tego filtra.\x28
i\x29
nadal są nawiasami.'\x28' === '('
.W ES6 masz tak zwane literały szablonów tagowanych .
Na przykład:
źródło