Gibt es eine sichere Möglichkeit, 'call' aufzurufen, um eine Funktion in JavaScript aufzurufen?

8

Ich möchte eine Funktion mit einem benutzerdefinierten thisArg aufrufen.

Das klingt trivial, ich muss nur call :

aufrufen %Vor%

Aber warte! func.call ist möglicherweise nicht Function.prototype.call .

Also habe ich über die Verwendung von

nachgedacht %Vor%

Aber warte! Function.prototype.call.call ist möglicherweise nicht Function.prototype.call .

Nehmen wir also an, dass Function.prototype.call das native ist, aber wenn man bedenkt, dass beliebige nicht-interne Eigenschaften hinzugefügt wurden, bietet ECMAScript einen sicheren Weg, um Folgendes zu tun?

%Vor%     
Oriol 26.06.2015, 15:18
quelle

3 Antworten

4

Das ist die Macht (und das Risiko) der Ente Typisierung: if typeof func.call === 'function' , dann sollten Sie es behandeln, als ob es eine normale, aufrufbare Funktion wäre. Es obliegt dem Anbieter von func sicherzustellen, dass die Eigenschaft call der öffentlichen Signatur entspricht. Ich benutze das an einigen Stellen, da JS keine Möglichkeit bietet, den Operator () zu überladen und einen klassischen Funktor bereitzustellen.

Wenn Sie wirklich func.call vermeiden möchten, würde ich mit func() gehen und func verlangen, um thisArg als erstes Argument zu verwenden. Da func() nicht an call delegiert (d. H.% Co_de% entlädt sich nicht zu f(g, h) ) und Sie können Variablen auf der linken Seite von Parens verwenden, so erhalten Sie vorhersagbare Ergebnisse.

Sie können auch einen Verweis auf f.call(t, g, h) zwischenspeichern, wenn Ihre Bibliothek geladen wird, falls sie später ersetzt wird, und damit später Funktionen aufrufen. Dies ist ein Muster, das von lodash / underscore verwendet wird, um native Array-Methoden zu erfassen, bietet jedoch keine tatsächliche Garantie, dass Sie die ursprüngliche native Aufrufmethode erhalten. Es kann ziemlich nah und ist nicht schrecklich hässlich:

%Vor%

Dies ist ein grundlegendes Problem in jeder Sprache mit Polymorphismus. Zu einem bestimmten Zeitpunkt müssen Sie dem Objekt oder der Bibliothek vertrauen, dass es sich gemäß seinem Vertrag verhält. Wie bei jedem anderen Fall, vertrauen Sie, aber verifizieren Sie:

%Vor%

Bei der Typprüfung können Sie auch eine Fehlerbehandlung durchführen:

%Vor%

Wenn Sie Function.prototype.call opfern können (oder erzwingen, dass es sich um ein tatsächliches Argument handelt), können Sie type-check und mit parens aufrufen:

%Vor%     
ssube 26.06.2015, 15:22
quelle
2

Irgendwann muss man darauf vertrauen, was im Fenster verfügbar ist. Es bedeutet entweder das Zwischenspeichern der Funktionen, die Sie verwenden möchten, oder der Versuch, den Code in der Sandbox zu verteilen.

Die "einfache" Lösung zum Aufrufen von call ist das vorübergehende Festlegen einer Eigenschaft:

%Vor%

Dies kann dann wie folgt verwendet werden:

%Vor%

Beachten Sie, dass die an safeCall übergebenen Parameter in einem Array zusammengefasst werden. Du brauchst apply , damit sich das korrekt verhält, und ich versuche hier nur die Abhängigkeiten zu vereinfachen.

verbesserte Version von safeCall Hinzufügen einer Abhängigkeit zu apply :

%Vor%

Dies kann wie folgt verwendet werden:

%Vor%

Eine alternative Lösung zum sicheren Aufruf von Call besteht darin, Funktionen aus einem anderen Fensterkontext zu verwenden.

Dies kann einfach durch Erstellen eines neuen iframe und Ergreifen von Funktionen aus dem Fenster erfolgen. Sie müssen immer noch davon ausgehen, dass eine gewisse Abhängigkeit von verfügbaren DOM-Bearbeitungsfunktionen besteht. Dies geschieht jedoch als ein Einrichtungsschritt, so dass zukünftige Änderungen das vorhandene Skript nicht beeinflussen:

%Vor%

Dies kann dann wie folgt verwendet werden:

%Vor%

Sowohl safeCall als auch sandboxCall sind sicher vor zukünftigen Änderungen in Function.prototype.call , aber wie Sie sehen können, sind sie auf einige existierende globale Funktionen angewiesen Laufzeit. Wenn ein böswilliges Skript vor diesem Code ausführt, ist Ihr Code weiterhin anfällig.

    
zzzzBov 26.06.2015 15:40
quelle
1

Wenn Sie Function.prototype.call vertrauen, können Sie Folgendes tun:

%Vor%

Wenn Sie Function..call aber nicht Function..call.call vertrauen, können Sie dies tun:

%Vor%

Und vielleicht wickeln Sie das sogar in einen Helfer ein.

Wenn Ihre Funktionen rein sind und Ihre Objekte serialisierbar sind, können Sie einen iFrame erstellen und per Nachrichtenübergabe ( window.postMessage ) den Funktionscode und die Argumente übergeben. Lassen Sie es call für Sie tun (da es ein neuer iframe ohne 3rd party code bist du ziemlich sicher), und du bist golden, etwas wie (überhaupt nicht getestet, wahrscheinlich mit Fehlern durchsetzt):

%Vor%

Das Gleiche kann mit Web Workers durchgeführt werden.

Wenn das der Fall ist, können Sie einen Schritt weiter gehen und es auf Ihren Server schicken. Wenn Sie einen Knoten ausführen, können Sie beliebige Skripts ziemlich sicher über das Modul vm ausführen. Unter Java hast du Projekte wie Rhino und Nashorn; Ich bin mir sicher, dass .Net eigene Implementierungen hat (vielleicht sogar als JScript!) Und es gibt wahrscheinlich ein paar bazillion gebrochene JavaScript-VMs, die in PHP implementiert sind.

Wenn Sie das tun , können Sie einen Dienst wie Runnable verwenden, um javascript direkt zu erstellen Sandboxes, vielleicht sogar Ihre eigene serverseitige Umgebung dafür.

    
Zirak 26.06.2015 15:54
quelle

Tags und Links