Wie verwendet man die Enten-Eingabe in Javascript, ohne immer nach Eigenschaften und Methoden zu suchen?

11

Ich weiß, dass Javascript Enten-Typisierung verwendet, und zuerst dachte ich, dies würde den Polymorphismus im Vergleich zu stark typisierten Sprachen wie C # vereinfachen. Aber jetzt sind meine Funktionen, die Argumente annehmen, übersät mit Dingen wie:

if(myObj.hasSomeProperty())

oder

if(myObj.hasSomeMethod())

oder

if(isNumber(myParam))

etc.

Das ist wirklich hässlich für mich. Ich komme aus einem C # -Hintergrund und finde definierte Schnittstellen viel besser.

Ich frage mich, ob ich fälschlicherweise versuche, Strategien anzuwenden, die in statisch typisierten Sprachen wirksam sind, und ob es eine bessere Möglichkeit gibt, dies in Javascript zu tun.

Ich weiß, ich konnte es einfach nicht überprüfen, aber das Aufspüren von Javascript-Laufzeitfehlern kann ein Albtraum sein, da sie nicht immer dort auftreten, wo der Fehler tatsächlich im Code auftritt.

Legion
quelle
2
Ich denke, Sie fummeln vielleicht nur an der Natur einer dynamisch typisierten Sprache herum. Man muss sich irgendwie daran gewöhnen, dass zur Laufzeit viele Fehler auftreten, anstatt zur Kompilierungszeit. Wenn Sie das Bedürfnis haben zu überprüfen, ob jedes Argument eine Zahl in jeder Funktion ist, die Zahlen eingibt, kann dies zu einer ziemlichen Belastung werden (obwohl es sich möglicherweise lohnt, wenn Sie eine Bibliothek versenden, bei der Sicherheit das oberste Ziel ist). Für alles, was skaliert, ist es wichtig, dass Funktionen nur dann fehlschlagen, wenn die falschen Typen übergeben werden. Stattdessen könnte ein produktiverer Fokus auf der Erstellung von Tests liegen.
Wo es hilfreich sein kann, diese Überprüfungen durchzuführen, um sicherzustellen, dass die Typen den erforderlichen Schnittstellenanforderungen entsprechen (z. B. um festzustellen, ob sie über die erforderlichen Methoden verfügen), befindet sich in Ihren zentralsten und am häufigsten verwendeten Funktionen (solche mit Instabilität = 0 mit dem efferente / afferente Kopplungsmetrik, die Martin bereitstellt). Das sollte ein ziemlich kleines Ziel sein. In der Regel gibt es viele einmalige lokale Funktionen, deren Umfang isoliert ist - diese benötigen wahrscheinlich keine so umfassenden Laufzeitprüfungen. Sie akkumulieren nicht viel Komplexität.
Wechseln Sie zu Type Script. Es ist immer noch duck-typisiert, unterstützt jedoch die statische Typisierung, um viele Fehler beim Kompilieren zu erkennen.
CodesInChaos
2
Sie sind auf das größte Problem beim Entenschreiben gestoßen: Seine Kraft beruht auf seiner Schwäche. Wenn Sie objektorientiertes JavaScript verwenden möchten, müssen Sie nur mit den Laufzeitfehlern leben und hoffen, dass Ihre Komponententests sie bald nach dem Erstellen finden :-(
Ross Patterson
@ RossPatterson Das OPs-Problem liegt in der dynamischen Eingabe, nicht in der Ententypisierung. TypeScript und Go sind beide vom Typ Ente, vermeiden jedoch das Problem des OP. Das Problem bei der Ententypisierung ist ein anderes: Sie können Mitglieder haben, die den Ententest bestehen, aber den erwarteten Vertrag nicht erfüllen.
CodesInChaos

Antworten:

11

Wie verwendet man die Enten-Eingabe in Javascript, ohne immer nach Eigenschaften und Methoden zu suchen?

Einfach: Suchen Sie nicht immer nach Eigenschaften und Methoden.

In Ruby heißt das, was Sie nennen, "Chicken Typing". In einer dynamisch ententypisierten Sprache vertrauen Sie einfach darauf, dass der Anrufer Ihnen ein geeignetes Objekt übergibt. Es ist die Aufgabe des Anrufers, seine Vertragsseite einzuhalten.

Ich weiß, dass Javascript Enten-Typisierung verwendet, und zuerst dachte ich, dies würde den Polymorphismus im Vergleich zu stark typisierten Sprachen wie C # vereinfachen.

Sie verwechseln hier mehrere orthogonale Tippachsen. Es gibt vier orthogonale Tippachsen:

  • Wann : Dynamische Typisierung (Typen sind bis zur Laufzeit nicht bekannt und werden nicht überprüft) vs. statische Typisierung (Typen sind vor der Laufzeit bekannt und werden überprüft)
  • Was : Ententypisierung (Typen basieren auf Verhalten ), strukturelle Typisierung (Typen basieren auf Struktur ) und nominelle Typisierung (Typen basieren auf Namen )
  • Kannst du sie sehen? explizite Typisierung (die Typen müssen explizit kommentiert werden) vs. implizite Typisierung (Typen werden abgeleitet)
  • Starkes Tippen vs. Schwaches Tippen - Sie haben vielleicht bemerkt, dass ich diesem Titel weder einen eingängigen Titel noch eine Erklärung in Klammern gegeben habe, weil diese beiden Begriffe im Gegensatz zu den sieben oben genannten Begriffen, die jeweils eine einzige allgemein akzeptierte genaue Definition haben haben ungefähr ein Dutzend halb weit verbreitete vage Definitionen, die sich widersprechen; Idealerweise sollten Sie diese Begriffe ganz vermeiden, und wenn Sie sie verwenden müssen , definieren Sie sie zuerst genau

Da Sie C # erwähnt haben: Es ist meistens statisch typisiert, unterstützt jedoch die dynamische Typisierung durch den Typ dynamic. Es ist meistens nominal typisiert, aber anonyme Typen verwenden strukturelle Typisierung, und syntaktische Muster (wie die Syntax des LINQ-Abfrageverständnisses) können als Enten bezeichnet werden -typed oder strukturell typisiert, wird meistens explizit typisiert, unterstützt jedoch die implizite Typisierung für generische Typargumente und lokale Variablen (obwohl der Fall lokaler Variablen im Vergleich zu den meisten anderen Sprachen ziemlich seltsam ist, da Sie den Typ nicht einfach weglassen können, sondern müssen Geben Sie ihm einen expliziten PseudotypvarMit anderen Worten, wenn Sie einen impliziten Typ möchten, müssen Sie dies explizit sagen. Ob C # stark oder schwach typisiert ist oder nicht, hängt davon ab, welche Definition der beiden verwendeten Begriffe Sie verwenden. Beachten Sie jedoch, dass es in C # viele Laufzeitfehler geben kann, insbesondere aufgrund der unsicheren Array-Kovarianz.

Ich weiß, ich konnte es einfach nicht überprüfen, aber das Aufspüren von Javascript-Laufzeitfehlern kann ein Albtraum sein, da sie nicht immer dort auftreten, wo der Fehler tatsächlich im Code auftritt.

Das Debuggen ist nicht leicht zu erlernen. Es gibt jedoch Techniken, die das Debuggen vereinfachen, z. B. Saff Squeeze, eine von Kent Beck beschriebene Technik, bei der Tests und Refactoring zum Debuggen verwendet werden:

Hit 'em High, Hit' em Low :

Regressionstests und der Saff Squeeze

Kent Beck, Drei-Flüsse-Institut

Zusammenfassung: Um einen Fehler effektiv zu isolieren, beginnen Sie mit einem Test auf Systemebene und inline und beschneiden Sie ihn schrittweise, bis Sie den kleinstmöglichen Test haben, der den Fehler nachweist.

Jörg W Mittag
quelle
Dieser Hit-Em-High-Hit-Em-Low-Link erhält für mich einen http 500, wobei "Seite nicht mehr verfügbar" die menschlich orientierte Nachricht ist.
Joshp
Die Domain threeriversinstitute.org scheint aufgegeben worden zu sein.
Bart van Ingen Schenau
Ah, verdammt. Und es ist nicht einmal auf der WayBack-Maschine archiviert .
Jörg W Mittag
Wie soll der Anrufer seine Vertragsseite einhalten? Es scheint, als gäbe es keine Möglichkeit (im Code) zu kommunizieren, wie die Parameter lauten sollten. Jede Funktion hat die Formfunktion fname (objParam, objParam, ...). Bedeutet dies, dass Sprachen wie Javascript vollständig von externer Dokumentation abhängig sind, um die Verwendung zu kommunizieren?
Legion
@Legion: Dokumentation, gute Benennung, gesunder Menschenverstand, Tests als Verhaltensspezifikationen, Lesen des Quellcodes, Sie nennen ihn. Beachten Sie, dass sich dies nicht wesentlich von schwächeren Typsystemen wie C # oder Java unterscheidet: ZB ist die Bedeutung des Rückgabewerts von IComparer<T>.Compare(T, T)nur aus der Dokumentation ersichtlich, nicht aus dem Typ. Und wo in der Art java.util.Collections.binarySearch(java.util.List<T>)steht, dass die…
Jörg W Mittag
1

Ich weiß, ich konnte es einfach nicht überprüfen, aber das Aufspüren von Javascript-Laufzeitfehlern kann ein Albtraum sein, da sie nicht immer dort auftreten, wo der Fehler tatsächlich im Code auftritt.

In der Tat ist die typische Praxis nicht zu überprüfen. Und ja, dies bedeutet, dass Sie Javascript-Fehler erhalten, die an anderer Stelle vom eigentlichen Problem gemeldet werden. In der Praxis ist dies jedoch kein großes Problem.

Wenn ich mit Javascript arbeite, teste ich ständig, was ich schreibe. In den meisten Codes habe ich Unit-Tests, die jedes Mal automatisch ausgeführt werden, wenn ich meinen Editor speichere. Wenn etwas unerwartet schief geht, weiß ich es fast sofort. Ich habe einen sehr kleinen Codebereich, in dem ich möglicherweise den Fehler gemacht habe, da es fast immer das letzte ist, was ich berührt habe, das den Fehler aufweist.

Wenn ich einen Laufzeitfehler erhalte, habe ich zumindest den Stack-Trace, und im Falle eines In-Browser-Fehlers habe ich die Möglichkeit, zu einer beliebigen Ebene des Stack-Trace zu wechseln und die Variablen zu überprüfen. Es ist normalerweise einfach, zurückzuverfolgen, woher der schlechte Wert stammt, und ihn somit auf das ursprüngliche Problem zurückzuführen.

Wenn Sie wie ich sind, als ich hauptsächlich in statisch typisierten Sprachen schrieb, habe ich vor dem Testen größere Codeblöcke geschrieben, und ich hatte keine Übung darin, einen Wert zurückzuverfolgen, von dem er stammt. Das Programmieren in einer Sprache wie Javascript ist anders, Sie müssen unterschiedliche Fähigkeiten anwenden. Ich vermute, dass eine solche Programmierung viel schwieriger erscheint, da dies nicht die Fähigkeiten sind, die Sie in anderen Sprachen wie C # entwickelt haben.

Trotzdem denke ich, dass es für explizite Typen viel zu sagen gibt. Sie eignen sich hervorragend zur Dokumentation und zum frühzeitigen Erkennen von Fehlern. Ich denke, dass wir in Zukunft zunehmend Dinge wie Flow und Typescript übernehmen werden, die dem Javascript die statische Typprüfung hinzufügen.

Winston Ewert
quelle
0

Ich denke, Sie tun das Richtige, Sie müssen nur den Stil finden, der für Ihr Auge angenehmer ist. Hier sind ein paar Ideen:

  • Anstelle von if(myObj.hasSomeProperty())Ihnen könnte verwenden if( myobj.prop !== undefined ). Dies funktioniert übrigens nur im nicht strengen Modus, in dem strengen Modus, den Sie verwenden müssten if( typeof myobj.prop !== 'undefined' ).

  • Sie können einige der Typprüfungen an separate Validatoren auslagern. Dies hat den Vorteil, dass die Validierung übersprungen werden kann, sobald die Schnittstellen ausgereift sind, z. B. if( is_valid( myobject ))wo mit is_validbeginnt if( !DEBUG ) return true;.

  • Manchmal ist es sinnvoll, Eingaben in eine kanonische Form zu klonen. In diesem Fall können Sie die verschiedenen Validierungsziele in der Klonfunktion / dem Klonobjekt sammeln. Beispielsweise könnte my_data = Data( myobj, otherstuff )der DataKonstruktor im Konstruktor bequem alle verschiedenen Validierungen an einer zentralen Stelle ausführen.

  • Sie könnten eine Bibliothek verwenden, die (gegen eine Leistungsgebühr) Ihre Typüberprüfung in etwas Eleganteres rationalisiert. Auch wenn Sie diesen Weg auf lange Sicht nicht nehmen, finden Sie es vielleicht bequem, Sie reibungslos in Ihren eigenen Stil zu bringen. Einige Beispiele hierfür sind xtype.js , Typprüfung , validator.js usw.

avnr
quelle