Mir wurde heute gesagt, dass es möglich ist, eine Funktion ohne Klammern aufzurufen. Ich konnte mir nur vorstellen, Funktionen wie apply
oder zu verwenden call
.
f.apply(this);
f.call(this);
Aber diese erfordern Klammern apply
und call
lassen uns auf dem ersten Platz. Ich dachte auch über die Idee nach, die Funktion an eine Art Ereignishandler zu übergeben, wie zum Beispiel setTimeout
:
setTimeout(f, 500);
Aber dann lautet die Frage: "Wie rufst du setTimeout
ohne Klammern auf?"
Was ist die Lösung für dieses Rätsel? Wie können Sie eine Funktion in Javascript aufrufen, ohne Klammern zu verwenden?
javascript
Mike Cluck
quelle
quelle
<insert any solution>
objektiv besser oder nützlicher ist alsf()
.Antworten:
Es gibt verschiedene Möglichkeiten, eine Funktion ohne Klammern aufzurufen.
Nehmen wir an, Sie haben diese Funktion definiert:
Dann folgen hier einige Möglichkeiten, um
greet
ohne Klammern aufzurufen :1. Als Konstruktor
Mit können
new
Sie eine Funktion ohne Klammern aufrufen:Von MDN auf dem
new
Oprator :2. As
toString
odervalueOf
ImplementierungtoString
undvalueOf
sind spezielle Methoden: Sie werden implizit aufgerufen, wenn eine Konvertierung erforderlich ist:Sie können dieses Muster (ab) verwenden, um
greet
ohne Klammern aufzurufen :Oder mit
valueOf
:valueOf
undtoString
werden tatsächlich von der @@ toPrimitive- Methode (seit ES6) aufgerufen , sodass Sie diese Methode auch implementieren können :2.b Überschreiben
valueOf
des FunktionsprototypsSie können die vorherige Idee verwenden, um die
valueOf
Methode für denFunction
Prototyp zu überschreiben :Sobald Sie das getan haben, können Sie schreiben:
Und obwohl es in der Folge Klammern gibt, enthält der eigentliche auslösende Aufruf keine Klammern. Weitere Informationen hierzu finden Sie im Blog "Aufrufen von Methoden in JavaScript, ohne sie wirklich aufzurufen".
3. Als Generator
Sie können eine Generatorfunktion (mit
*
) definieren, die einen Iterator zurückgibt . Sie können es mit der Spread-Syntax oder mit derfor...of
Syntax aufrufen .Zuerst brauchen wir eine Generatorvariante der ursprünglichen
greet
Funktion:Und dann rufen wir es ohne Klammern auf, indem wir die Iterator- Methode @@ definieren :
Normalerweise haben Generatoren
yield
irgendwo ein Schlüsselwort, aber es wird nicht benötigt, damit die Funktion aufgerufen wird.Die letzte Anweisung ruft die Funktion auf, aber das könnte auch mit Destrukturierung geschehen :
oder ein
for ... of
Konstrukt, aber es hat eigene Klammern:Beachten Sie, dass Sie können die oben mit dem Original zu tun
greet
und Funktion, aber es wird eine Ausnahme in den Prozess auslösen, nachdemgreet
ausgeführt wurde (getestet auf FF und Chrome). Sie können die Ausnahme mit einemtry...catch
Block verwalten.4. Als Getter
@ jehna1 hat eine vollständige Antwort darauf, also gib ihm Anerkennung. Hier ist eine Möglichkeit, eine Funktion ohne Klammern für den globalen Bereich aufzurufen , wobei die veraltete
__defineGetter__
Methode vermieden wird. Es wirdObject.defineProperty
stattdessen verwendet.greet
Dazu müssen wir eine Variante der ursprünglichen Funktion erstellen :Und dann:
Ersetzen Sie
window
durch was auch immer Ihr globales Objekt ist.Sie können die ursprüngliche
greet
Funktion aufrufen, ohne eine Spur für das globale Objekt zu hinterlassen:Man könnte jedoch argumentieren, dass wir hier Klammern haben (obwohl sie nicht am eigentlichen Aufruf beteiligt sind).
5. Als Tag-Funktion
Seit ES6 können Sie eine Funktion aufrufen, die ihr ein Vorlagenliteral mit folgender Syntax übergibt :
Siehe "Tagged Template Literals" .
6. Als Proxy-Handler
Seit ES6 können Sie einen Proxy definieren :
Wenn Sie dann einen beliebigen Eigenschaftswert lesen, wird Folgendes aufgerufen
greet
:Es gibt viele Variationen davon. Noch ein Beispiel:
7. Als Instanzprüfer
Der
instanceof
Operator führt die@@hasInstance
Methode für den zweiten Operanden aus, wenn er definiert ist:quelle
valueOf
.func``;
'1' |> alert
Der einfachste Weg, dies zu tun, ist mit dem
new
Bediener:Das ist zwar unorthodox und unnatürlich, funktioniert aber und ist vollkommen legal.
Der
new
Operator benötigt keine Klammern, wenn keine Parameter verwendet werden.quelle
!f
führt zu demselben Ergebnis, ohne eine Instanz der Konstruktorfunktion zu instanziieren (für die ein neuer Kontext erstellt werden muss). Es ist viel leistungsfähiger und wird in vielen gängigen Bibliotheken (wie Bootstrap) verwendet.+
,-
,~
) in solchen Bibliotheken, ist ein Byte in der minimierten Version der Bibliothek zu speichern , wo der Rückgabewert ist nicht erforderlich. (dh!function(){}()
) Die übliche selbstaufrufende Syntax ist(function(){})()
(leider ist die Syntaxfunction(){}()
nicht browserübergreifend). Da die oberste selbstaufrufende Funktion normalerweise nichts zurückzugeben hat, ist sie normalerweise das Ziel dieser Technik zum Speichern von Bytesfunction foo() { alert("Foo!") };
Zum Beispiel:!foo
kehrt zurückfalse
Sie können Getter und Setter verwenden.
Führen Sie dieses Skript nur mit:
Bearbeiten:
Wir können sogar argumentieren!
Bearbeiten 2:
Sie können auch globale Funktionen definieren, die ohne Klammern ausgeführt werden können:
Und mit Argumenten:
Haftungsausschluss:
Wie @MonkeyZeus sagte: Niemals dürfen Sie diesen Code in der Produktion verwenden, egal wie gut Ihre Absichten sind.
quelle
__defineGetter__
veraltet ist. Verwenden SieObject.defineProperty
stattdessen.Hier ist ein Beispiel für eine bestimmte Situation:
Diese Anweisung wird zwar nicht aufgerufen , führt aber zu einem zukünftigen Aufruf .
Aber ich denke, Grauzonen könnten für solche Rätsel in Ordnung sein :)
quelle
Wenn wir einen Ansatz des Querdenkens akzeptieren, gibt es in einem Browser mehrere APIs, die wir missbrauchen können, um beliebiges JavaScript auszuführen, einschließlich des Aufrufs einer Funktion, ohne tatsächliche Klammerzeichen.
1.
location
undjavascript:
Protokoll:Eine solche Technik besteht darin, das
javascript:
Protokoll bei derlocation
Zuweisung zu missbrauchen .Arbeitsbeispiel:
Obwohl technisch
\x28
und\x29
immer noch in Klammern, sobald der Code ausgewertet wird, ist der tatsächliche(
und das)
Zeichen nicht angezeigt. Die Klammern werden in einer JavaScript-Zeichenfolge maskiert, die bei der Zuweisung ausgewertet wird.2.
onerror
undeval
:Ebenso können wir je nach Browser das Globale missbrauchen
onerror
, indem es auf setzeneval
und etwas auslösen, das zu gültigem JavaScript führt. Dieser ist schwieriger, da Browser in diesem Verhalten inkonsistent sind, aber hier ist ein Beispiel für Chrome.Arbeitsbeispiel für Chrome (nicht Firefox, andere ungetestet):
Dies funktioniert in Chrome, da
throw'test'
es'Uncaught test'
als erstes Argument anonerror
das fast gültige JavaScript übergeben wird. Wenn wir es stattdessen tunthrow';test'
, wird es vergehen'Uncaught ;test'
. Jetzt haben wir gültiges JavaScript! Definieren Sie einfachUncaught
den Test und ersetzen Sie ihn durch die Nutzlast.Abschließend:
Solcher Code ist wirklich schrecklich und sollte niemals verwendet werden , wird aber manchmal bei XSS-Angriffen verwendet, sodass die Moral der Geschichte nicht darauf beruht, Klammern zu filtern, um XSS zu verhindern. Die Verwendung eines CSP zur Verhinderung eines solchen Codes wäre ebenfalls eine gute Idee.
quelle
eval
und Schreiben der Zeichenfolge, ohne die Klammern zu verwenden?eval
erfordert aber normalerweise Klammern, daher dieser Filter-Ausweich-Hack.\x28
und\x29
sind immer noch Klammern.'\x28' === '('
.In ES6 haben Sie sogenannte Tagged Template Literals .
Beispielsweise:
quelle