Aufruf einer Funktion ohne Klammern

Lesezeit: 10 Minuten

Mir wurde heute gesagt, dass es möglich ist, eine Funktion ohne Klammern aufzurufen. Die einzige Möglichkeit, die mir einfiel, war die Verwendung von Funktionen wie apply oder call.

f.apply(this);
f.call(this);

Aber diese erfordern Klammern auf apply und call uns auf Platz eins verlassen. Ich habe auch überlegt, die Funktion an eine Art Event-Handler wie z setTimeout:

setTimeout(f, 500);

Aber dann stellt sich die Frage: “Wie rufen Sie auf setTimeout ohne Klammern?”

Was ist also die Lösung für dieses Rätsel? Wie können Sie eine Funktion in Javascript aufrufen, ohne Klammern zu verwenden?

  • Ich versuche nicht, unhöflich zu sein, aber ich muss fragen: Warum?

    – jehna1

    11. März 16 um 20:45 Uhr

  • @ jehna1 Weil ich eine Frage beantwortet habe, wie Funktionen aufgerufen werden, und korrigiert wurde, als ich sagte, dass sie am Ende Klammern benötigen.

    – Mike Gluck

    11. März 16 um 20:46 Uhr


  • Tolle! Ich hätte nicht gedacht, dass diese Frage so viel Zugkraft haben würde. Vielleicht hätte ich sie selbst stellen sollen 🙂

    – Amit

    12. März 16 um 6:17 Uhr

  • Das ist die Art von Frage, die mir das Herz bricht. Welchen Nutzen könnte ein solcher Missbrauch und eine solche Ausbeutung bringen? Ich möchte einen gültigen Anwendungsfall wissen, wo <insert any solution> ist objektiv besser oder nützlicher als f().

    – Mulan

    13. März 16 um 19:37 Uhr

  • @Aaron: Sie sagen, es gibt keinen triftigen Grund, aber wie die Antwort von Alexander O’Mara zeigt, könnte man sich die Frage stellen, ob das Entfernen von Klammern ausreicht, um die Codeausführung zu verhindern – oder was ist mit einem verschleierten Javascript-Wettbewerb? Natürlich ist es ein absurdes Ziel, wartbaren Code zu schreiben, aber es ist eine amüsante Frage.

    – PJTrail

    16. März 16 um 15:23 Uhr

Aufruf einer Funktion ohne Klammern
Trinkot

Es gibt verschiedene Möglichkeiten, eine Funktion ohne Klammern aufzurufen.

Nehmen wir an, Sie haben diese Funktion definiert:

function greet() {
    console.log('hello');
}

Dann folgen hier einige Anrufmöglichkeiten greet ohne Klammern:

1. Als Konstrukteur

Mit new Sie können eine Funktion ohne Klammern aufrufen:

new greet; // parentheses are optional in this construct.

Von MDN auf der new Betreiber:

Syntax

new constructor[([arguments])]

2. Als toString oder valueOf Implementierung

toString und valueOf sind spezielle Methoden: Sie werden implizit aufgerufen, wenn eine Konvertierung erforderlich ist:

var obj = {
    toString: function() {
         return 'hello';
    }
}

'' + obj; // concatenation forces cast to string and call to toString.

Sie könnten dieses Muster zum Anrufen (missbrauchen) verwenden greet ohne Klammern:

'' + { toString: greet };

Oder mit valueOf:

+{ valueOf: greet };

valueOf und toString werden in der Tat von der aufgerufen @@zuPrimitiv Methode (seit ES6), und so können Sie auch implementieren das Methode:

+{ [Symbol.toPrimitive]: greet }
"" + { [Symbol.toPrimitive]: greet }

2.b Überschreiben valueOf im Funktionsprototyp

Sie könnten die vorherige Idee übernehmen, um das zu überschreiben valueOf Methode auf der Function Prototyp:

Function.prototype.valueOf = function() {
    this.call(this);
    // Optional improvement: avoid `NaN` issues when used in expressions.
    return 0; 
};

Wenn Sie das getan haben, können Sie schreiben:

+greet;

Und obwohl es auf der ganzen Linie Klammern gibt, hat der eigentliche auslösende Aufruf keine Klammern. Mehr dazu im Blog “Methoden in JavaScript aufrufen, ohne sie wirklich aufzurufen”

3. Als Generator

Sie könnten a definieren Generatorfunktion (mit *), die eine zurückgibt Iterator. Sie können es mit aufrufen Spread-Syntax oder mit dem for...of Syntax.

Zuerst brauchen wir eine Generatorvariante des Originals greet Funktion:

function* greet_gen() {
    console.log('hello');
}

Und dann nennen wir es ohne Klammern, indem wir die definieren @@Iterator Methode:

[...{ [Symbol.iterator]: greet_gen }];

Normalerweise hätten Generatoren a yield Schlüsselwort irgendwo, aber es ist nicht erforderlich, damit die Funktion aufgerufen wird.

Die letzte Anweisung ruft die Funktion auf, aber das könnte auch damit gemacht werden Destrukturierung:

[,] = { [Symbol.iterator]: greet_gen };

oder ein for ... of konstruieren, aber es hat eigene Klammern:

for ({} of { [Symbol.iterator]: greet_gen });

Beachten Sie, dass Sie kann Machen Sie das oben mit dem Original greet funktionieren auch, aber es wird eine Ausnahme im Prozess auslösen, nach greet wurde ausgeführt (getestet auf FF und Chrome). Sie könnten die Ausnahme mit a verwalten try...catch Block.

4. Als Getter

@ jehna1 hat eine vollständige Antwort darauf, also gib ihm Anerkennung. Hier ist eine Möglichkeit, eine Funktion aufzurufen Klammern-weniger auf globaler Ebene, Vermeidung der veraltet __defineGetter__ Methode. Es benutzt Object.defineProperty stattdessen.

Wir müssen eine Variante des Originals erstellen greet Funktion dazu:

Object.defineProperty(window, 'greet_get', { get: greet });

Und dann:

greet_get;

Ersetzen window mit was auch immer Ihr globales Objekt ist.

Man könnte das Original nennen greet funktionieren, ohne eine Spur auf dem globalen Objekt zu hinterlassen, wie folgt:

Object.defineProperty({}, 'greet', { get: greet }).greet;

Aber man könnte argumentieren, dass wir hier Klammern haben (obwohl sie nicht an der eigentlichen Invokation beteiligt sind).

5. Als Tag-Funktion

Seit ES6 können Sie eine Funktion aufrufen, indem Sie a übergeben Vorlagenliteral mit dieser Syntax:

greet``;

Sehen “Tagged Template-Literale”.

6. Als Proxy-Handler

Seit ES6 können Sie a definieren Proxy:

var proxy = new Proxy({}, { get: greet } );

Und dann wird das Lesen eines beliebigen Eigenschaftswerts aufgerufen greet:

proxy._; // even if property not defined, it still triggers greet

Davon gibt es viele Variationen. Noch ein Beispiel:

var proxy = new Proxy({}, { has: greet } );

1 in proxy; // triggers greet

7. Als Instanzprüfer

Der instanceof Operator führt die aus @@hasInstance Methode auf dem zweiten Operanden, wenn definiert:

1 instanceof { [Symbol.hasInstance]: greet } // triggers greet

  • Das ist ein sehr interessanter Ansatz mit valueOf.

    – Mike Gluck

    11. März 16 um 21:55 Uhr

  • Sie haben ES6 vergessen: func``;

    – Ismael Miguel

    12. März 16 um 15:23 Uhr

  • Sie haben Klammern verwendet, indem Sie eval aufgerufen haben 🙂

    – Trinkot

    16. März 16 um 13:58 Uhr


  • In diesem Fall wird die Funktion nicht ausgeführt, sondern an den Aufrufer übergeben.

    – Trinkot

    9. April 17 um 10:27 Uhr

  • @trincot Eine andere Methode wird bald mit möglich sein Pipeline-Betreiber: '1' |> alert

    – Artur

    11. März 18 um 11:03 Uhr


Aufruf einer Funktion ohne Klammern
Amit

Am einfachsten geht das mit der new Operator:

function f() {
  alert('hello');
}

new f;

Das ist zwar unorthodox und unnatürlich, aber es funktioniert und ist vollkommen legal.

Der new Der Operator benötigt keine Klammern, wenn keine Parameter verwendet werden.

  • Korrektur, der einfachste Weg, dies zu tun, besteht darin, einen Operanden voranzustellen, der die Auswertung des Funktionsausdrucks erzwingt. !f führt zum selben Ergebnis, ohne dass eine Instanz der Konstruktorfunktion instanziiert wird (was die Erstellung eines neuen this-Kontexts erfordert). Es ist viel leistungsfähiger und wird in vielen beliebten Bibliotheken (wie Bootstrap) verwendet.

    – DER Tschad

    13. März 16 um 5:11 Uhr

  • @THEtheChad – Das Auswerten eines Ausdrucks ist nicht dasselbe wie das Ausführen einer Funktion, aber wenn Sie eine andere (schönere? überraschendere?) Methode zum Aufrufen (Ausführen) einer Funktion haben – posten Sie eine Antwort!

    – Amit

    13. März 16 um 5:43 Uhr

  • Der Punkt, an dem ein Ausrufezeichen oder ein anderer unärer Operator mit einem Zeichen (+, -, ~) in solchen Bibliotheken besteht darin, ein Byte in der minimierten Version der Bibliothek zu speichern, wo der Rückgabewert nicht benötigt wird. (dh !function(){}()) Die übliche selbstaufrufende Syntax ist (function(){})() (Leider die Syntax function(){}() ist nicht browserübergreifend) Da die oberste selbstaufrufende Funktion normalerweise nichts zurückzugeben hat, ist sie normalerweise das Ziel dieser Byte-Spartechnik

    – Ultimater

    1. November 16 um 6:05 Uhr

  • @THEtheChad Stimmt das? Ich habe es gerade in Chrome ausprobiert und bekam keine Funktionsausführung. function foo() { alert("Foo!") }; Beispielsweise: !foo kehrt zurück false

    – Glenn ‚devalias‘ Grant

    30. März 17 um 0:11 Uhr


Aufruf einer Funktion ohne Klammern
jehna1

Sie können Getter und Setter verwenden.

var h = {
  get ello () {
    alert("World");
  }
}

Führen Sie dieses Skript einfach mit:

h.ello  // Fires up alert "world"

Bearbeiten:

Wir können sogar argumentieren!

var h = {
  set ello (what) {
    alert("Hello " + what);
  }
}

h.ello = "world" // Fires up alert "Hello world"

Bearbeiten 2:

Sie können auch globale Funktionen definieren, die ohne Klammern ausgeführt werden können:

window.__defineGetter__("hello", function() { alert("world"); });
hello;  // Fires up alert "world"

Und mit Argumenten:

window.__defineSetter__("hello", function(what) { alert("Hello " + what); });
hello = "world";  // Fires up alert "Hello world"

Haftungsausschluss:

Wie @MonkeyZeus feststellte: Niemals sollten Sie dieses Stück Code in der Produktion verwenden, egal wie gut Ihre Absichten sind.

  • Genau genommen aus dem POV von “Ich bin ein axtschwingender Verrückter, der die Ehre hat, Ihren Code zu übernehmen, weil Sie zu größeren und besseren Dingen übergegangen sind; dennoch weiß ich, wo Sie leben”. Ich hoffe wirklich, dass das nicht normal ist lol. Die Verwendung innerhalb eines Plug-Ins, das Sie pflegen, ist akzeptabel. Schreiben Sie Geschäftslogik-Code, bitte halten Sie inne, während ich meine Axt schärfe 🙂

    – AffeZeus

    11. März 16 um 22:15 Uhr

  • @MonkeyZeus haha, ja! Haftungsausschluss für zukünftige Programmierer hinzugefügt, die dies bei Google finden können

    – jehna1

    11. März 16 um 22:23 Uhr

  • Eigentlich ist dieser Haftungsausschluss zu hart. Es gibt legitime Anwendungsfälle für “Getter als Funktionsaufruf”. Tatsächlich wird es ausgiebig in einer sehr erfolgreichen Bibliothek verwendet. (Möchtest du einen Tipp? 🙂

    – Amit

    12. März 16 um 23:48 Uhr

  • Beachten Sie, dass __defineGetter__ ist veraltet. Benutzen Object.defineProperty stattdessen.

    – Felix Klinge

    13. März 16 um 19:33 Uhr

  • @MonkeyZeus – wie ich ausdrücklich schrieb im Kommentar – dieser Stil des Funktionsaufrufs wird benutztausführlich und absichtlich, in einer sehr erfolgreichen öffentlichen Bibliothek als API selbst, nicht intern.

    – Amit

    14. März 16 um 23:00 Uhr


Hier ist ein Beispiel für eine bestimmte Situation:

window.onload = funcRef;

Obwohl diese Aussage nicht wirklich ist aufrufen aber führt zu a zukünftige Berufung.

Aber ich denke, Grauzonen könnten für Rätsel wie dieses in Ordnung sein 🙂

1644072378 451 Aufruf einer Funktion ohne Klammern
Alexander O’Mara

Wenn wir einen lateralen Denkansatz 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 und javascript: Protokoll:

Eine solche Technik besteht darin, das zu missbrauchen javascript: Protokoll an location Abtretung.

Arbeitsbeispiel:

location='javascript:alertx281x29'

Obwohl technisch x28 und x29 sind immer noch Klammern, sobald der Code ausgewertet wird, die eigentliche ( und ) Zeichen erscheint nicht. Die Klammern werden in einer JavaScript-Zeichenfolge maskiert, die bei der Zuweisung ausgewertet wird.


2. onerror und eval:

Ebenso können wir je nach Browser die globale onerrorindem Sie es auf setzen eval, und etwas werfen, das zu gültigem JavaScript stringifiziert wird. Dieser ist kniffliger, da Browser in diesem Verhalten inkonsistent sind, aber hier ist ein Beispiel für Chrome.

Arbeitsbeispiel für Chrome (nicht Firefox, andere ungetestet):

window.onerror=eval;Uncaught=0;throw';alertx281x29';

Dies funktioniert in Chrome, weil throw'test' wird bestehen 'Uncaught test' als erstes Argument zu onerror, was fast gültiges JavaScript ist. Wenn wir es stattdessen tun throw';test' es wird vergehen 'Uncaught ;test'. Jetzt haben wir gültiges JavaScript! Einfach definieren Uncaughtund ersetzen Sie test durch die Nutzlast.


Abschließend:

Ein solcher Code ist wirklich schrecklichund sollte niemals verwendet werden, wird aber manchmal bei XSS-Angriffen verwendet, daher ist die Moral der Geschichte, sich nicht auf das Filtern von Klammern zu verlassen, um XSS zu verhindern. Verwendung einer CSP es wäre auch eine gute Idee, solchen Code zu verhindern.

  • Ist das nicht dasselbe wie benutzen eval und Schreiben der Zeichenfolge, ohne tatsächlich die Klammerzeichen zu verwenden.

    – Zev Spitz

    14. März 16 um 08:03 Uhr


  • @ZenSpitz Ja, aber eval erfordert normalerweise Klammern, daher dieser Filterumgehung-Hack.

    – Alexander O’Mara

    14. März 16 um 08:05 Uhr


  • Wohl x28 und x29 sind immer noch Klammern. 'x28' === '('.

    – Trinkot

    14. März 16 um 10:01 Uhr

  • @trincot Das ist sozusagen der Punkt, den ich in der Antwort angesprochen habe, dies ist ein lateraler Denkansatz, der einen Grund aufzeigt, warum dies getan werden könnte. Ich habe es in der Antwort deutlicher gemacht.

    – Alexander O’Mara

    14. März 16 um 17:27 Uhr

  • Wer auch immer dafür gestimmt hat, dies zu löschen, lese bitte die Richtlinien zum Löschen von Antworten.

    – Alexander O’Mara

    14. März 16 um 17:54 Uhr


1644072378 426 Aufruf einer Funktion ohne Klammern
Idan Dagan

In ES6 haben Sie das, was genannt wird Markierte Template-Literale.

Beispielsweise:

function foo(val) {
    console.log(val);
}

foo`Tagged Template Literals`;

  • Ist das nicht dasselbe wie benutzen eval und Schreiben der Zeichenfolge, ohne tatsächlich die Klammerzeichen zu verwenden.

    – Zev Spitz

    14. März 16 um 08:03 Uhr


  • @ZenSpitz Ja, aber eval erfordert normalerweise Klammern, daher dieser Filterumgehung-Hack.

    – Alexander O’Mara

    14. März 16 um 08:05 Uhr


  • Wohl x28 und x29 sind immer noch Klammern. 'x28' === '('.

    – Trinkot

    14. März 16 um 10:01 Uhr

  • @trincot Das ist sozusagen der Punkt, den ich in der Antwort behandelt habe. Dies ist ein Ansatz zum Querdenken, der einen Grund aufzeigt, aus dem dies getan werden könnte. Ich habe es in der Antwort deutlicher gemacht.

    – Alexander O’Mara

    14. März 16 um 17:27 Uhr

  • Wer auch immer dafür gestimmt hat, dies zu löschen, lese bitte die Richtlinien zum Löschen von Antworten.

    – Alexander O’Mara

    14. März 16 um 17:54 Uhr


.

784390cookie-checkAufruf einer Funktion ohne Klammern

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy