strenkel / jshero

JS Hero - Learn to code: JavaScript online tutorial with interactive exercises
https://www.jshero.net
Other
28 stars 10 forks source link

Fix const/let #27

Closed Paratron closed 5 years ago

Paratron commented 6 years ago

Hey, ich habe bei der letzten Aufgabe (quersumme) folgenden Code genutzt:

const quersumme = (input) => String(input).split('').reduce((acc, val) => acc + parseInt(val), 0);

Beim evaluieren kommt der Fehler "quersumme ist keine Funktion." Das kann nicht stimmen - obwohl ich eine moderne fat arrow function benutzt habe ist typeof quersumme dennoch function.

strenkel commented 6 years ago

Danke für den Hinweis! Da hast Du leider recht. Das ist ein Bug in JS Hero. Das Problem ist allerdings das const. Verwendest Du var sollte der Code funktionieren. const und let funktionieren nicht, da ich den eingegebenen Code einfach mit global eval auswerte. Ist die Funktion mit var deklariert, ist sie dann ausserhalb von global eval sichtbar und ich kann sie testen. Ist sie mit let oder const deklariert, ist sie ausserhalb von eval oder global eval nicht sichtbar. Und der Test sagt dann, dass quersumme keine Funktion ist.

Das muss ich unbedingt fixen! Wegen Zeitmangel allerdings erst Anfang Oktober.

Paratron commented 6 years ago

Dazu hätte ich eine Idee: Kannst du nicht zur Code-Ausführung einen iFrame platzieren und darin einen Script-Tag erzeugen, in welchen du den Code injizierst? Dann sparst du dir eval und hast den Vorteil dass aufgrund des iFrame der Code etwas abgeschottet läuft.

Wenn du den Code dann noch dekorierst, wie z.b. hier:

(() => {
    // ORIGINALER USERCODE HIER EINFÜGEN

    // Hier kommen die Prüfroutinen:
    if(typeof quersumme !== 'function'){
        jsheroApi.reportError('quersumme ist keine Funktion!');
    }
})();

Dann kannst du deine Prüfroutinen einfach unter den User-Code kleben und im gleichen Scope ausführen. Calls zu jsheroApi wären dann dafür zuständig Nachrichten aus dem iFrame heraus nach "oben" zum Kurs zu kommunizieren.

strenkel commented 6 years ago

Daran habe ich noch garnicht gedacht (also Code im iFrame laufen lassen). Allerdings führe ich das eval in einem Webworker aus, um Endlosschleifen abzufangen. Geht das auch mit iFrames? Also das ich in der Hauptseite das IFrame nach x Sekunden abschieße, wenn es kein Ergebnis liefert? Sollte eigentlich.

Bisher dachte ich, etwas sowas zu machen (alles in dem Webworker):

Zuerst ein leeres export Objekt zu definieren. In den Koans selber neben den Tests ein export-Feld hinzuzufügen. Dieses Export-Feld enthält den Namen der zu testenden Funktion. An den User-Code würde ich dann etwas folgende Zeile anfügen (als String):

export.functionUnderTest = koan.export;

... und den User-Code inklusive dieser Zeile in eval ausführen. Dann müsste ich nach dem eval über export.functionUnderTest auf die zu testende Funktion zugreifen können.

(Allerdings muss ich manchmal mehr als nur die zu testende Funktion exportieren. Z.B. Koan #69: Funktionen benutzen Funktionen)

Was ist besser?

Paratron commented 6 years ago

Naja, das kommt drauf an was dir am Wichtigsten ist...

Ich denke dass auch eine Endlosschleife im iFrame den Tab mit dem Kurs aufhängen würde. Allerdings hast du das Problem, dass du im Webworker komplett vom Browser abgeschottet bist. Das heisst keinerlei Zugriff auf den DOM und/oder window. Also auch sowas wie console.log gibts dann nicht.

Das mag genügen, wenn du einfach nur generell Javascript lehren willst. Aber damit schliesst du aus, dass du auch mal ein wenig auf die Browser API in Javascript eingehst.

strenkel commented 6 years ago

Abfangen von Endlosschleifen ist ein 'Muss'. Mindestens bei Aufgaben, bei denen es um Schleifen geht. Aber das mit der Browser API stimmt auch. Sowas habe ich im Kopf. Vielleicht muss ich dann beides machen: iFrame und webworker-eval.

Paratron commented 6 years ago

Jep, dachte ich auch grade. Einmal in einen Webworker geben um Endlosschleifen zu erkennen und dann im iFrame ausführen.

strenkel commented 6 years ago

Habe das jetzt mit eval gefixt. Es wird nicht mehr global-eval verwendet, sondern das normale eval. Der Testaufruf wird als String an den Übungscode angehängt und beides zusammen mit eval ausgewertet. Das Ergebnis des Testaufrufs wird durch das eval zurückgegeben. Als positiven Nebeneffekt ist es nicht mehr möglich, im Übungscode eine Testcode-Variable zu überschreiben (theoretisch schon, praktisch aber wohl nicht). Mögliche Verbesserung wäre noch, eval im strict mode zu verwenden. Die Auswertung im iFrame behalte ich im Hinterkopf.

Nochmals vielen Dank für die Bug-Meldung!!!