Das Buch "Wie JavaScript funktioniert"

Bild Die meisten Programmiersprachen sind aus einem alten Paradigma hervorgegangen, das zu Fortrans Zeiten stammt. Der JavaScript-Guru Douglas Crockford entwurzelt diese getrockneten Wurzeln und ermöglicht es uns, über die Zukunft der Programmierung nachzudenken und die Anforderungen für die nächste Sprache auf eine neue Ebene zu verstehen.

Der Autor beginnt mit den Grundlagen: Namen, Zahlen, logische Werte, Zeichen und andere grundlegende Informationen. Sie lernen nicht nur die Probleme und Schwierigkeiten bei der Arbeit mit Typen in JavaScript kennen, sondern auch, wie Sie diese umgehen können. Anschließend lernen Sie Datenstrukturen und -funktionen kennen, um die ihnen zugrunde liegenden Mechanismen zu verstehen, und lernen, wie Sie Funktionen höherer Ordnung und einen objektorientierten Programmierstil ohne Klassen verwenden.

Auszug
Wie Code ohne Klassen funktioniert


Und du denkst, dass du außerhalb aller Klassen klug und frei bist.
John Lennon

Eine der Schlüsselideen bei der Entwicklung der objektorientierten Programmierung war ein Modell für den Datenaustausch zwischen Programmteilen. Der Name der Methode und ihre Argumente müssen in Form von Nachrichten dargestellt werden. Ein Methodenaufruf sendet eine Nachricht an das Objekt. Jedes Objekt zeichnet sich durch ein eigenes Verhalten aus, das sich beim Empfang bestimmter Nachrichten manifestiert. Der Absender glaubt, dass der Empfänger weiß, was mit der Nachricht zu tun ist.

Ein zusätzlicher Vorteil ist der Polymorphismus. Jedes Objekt, das eine bestimmte Nachricht erkennt, hat das Recht, sie zu empfangen. Was als nächstes passiert, hängt von der Spezialisierung des Objekts ab. Und das ist ein sehr produktiver Gedanke.

Leider wurden wir durch die Vererbung abgelenkt - ein sehr effektives Schema für die Wiederverwendung von Code. Ihre Bedeutung hängt mit der Fähigkeit zusammen, die Arbeitskosten bei der Entwicklung eines Programms zu senken. Die Vererbung basiert auf einem ähnlichen Plan, mit Ausnahme einiger Nuancen. Wir können sagen, dass ein Objekt oder eine Klasse von Objekten einem anderen Objekt oder einer anderen Klasse von Objekten ähnlich ist, aber es gibt einige wichtige Unterschiede. In einer einfachen Situation funktioniert alles super. Es sei daran erinnert, dass das moderne OOP mit Smalltalk begann, einer Programmiersprache für Kinder. Wenn die Situation komplizierter wird, wird die Vererbung problematisch. Es entsteht ein starker Zusammenhalt der Klassen. Das Ändern einer Klasse kann in den davon abhängigen Klassen zu Fehlern führen. Module aus Klassen sind einfach nutzlos.

Darüber hinaus beobachten wir eine erhöhte Aufmerksamkeit für Eigenschaften und nicht für Objekte. Besonderes Augenmerk wird auf die Methoden zum Abrufen (get-Methoden) und Zuweisen (set-Methoden) von Werten zu jeder einzelnen Eigenschaft gelegt. In noch weniger erfolgreichen Projekten sind die Eigenschaften offen und können ohne Kenntnis des Objekts geändert werden. Es ist möglich, ein erfolgreicheres Projekt einzuführen, bei dem Eigenschaften ausgeblendet werden und Methoden Transaktionen verarbeiten, die sich nicht nur mit Eigenschaftsänderungen befassen. Dieser Ansatz wird jedoch nicht oft angewendet.

Darüber hinaus besteht eine zu große Typabhängigkeit. Typen wurden zu einem Merkmal von Fortran und späteren Sprachen, da sie für die Compiler-Ersteller praktisch waren. Seitdem ist die Mythologie um Typen gewachsen und hat extravagante Behauptungen aufgestellt, dass Typen das Programm vor Fehlern schützen. Trotz der Hingabe an Typen verließen Fehler nicht die tägliche Praxis.

Typen werden respektiert und für die Früherkennung von Fehlkalkulationen in der Kompilierungsphase gelobt. Je früher ein Versehen entdeckt wird, desto geringer sind die Kosten, um es zu beseitigen. Bei ordnungsgemäßem Testen des Programms werden all diese Fehlkalkulationen jedoch sehr schnell erkannt. Daher werden Typidentifikationsfehler als kostengünstig eingestuft.

Typen sind nicht für das Auftreten schwer zu erkennender und kostspieliger Fehler verantwortlich. Ihr Fehler liegt nicht im Auftreten von Problemen, die durch solche Fehler verursacht werden und einige Tricks erfordern. Typen können uns dazu bringen, obskure, verwirrende und zweifelhafte Programmiermethoden zu verwenden.

Typen sind wie eine Diät zur Gewichtsreduktion. Diät wird nicht der Rückkehr und Gewichtszunahme beschuldigt. Sie wird auch nicht als Ursache des Leidens oder der von ihr verursachten Gesundheitsprobleme angesehen. Diäten geben Hoffnung, dass das Gewicht zu einer gesunden Norm zurückkehren wird und wir weiterhin Junk Food essen werden.

Die klassische Vererbung lässt uns glauben, dass wir qualitativ hochwertige Programme erstellen, während wir mehr Fehler machen und immer ineffizientere Vererbungen anwenden. Wenn Sie die negativen Manifestationen ignorieren, scheinen die Typen ein großer Sieg zu sein. Die Vorteile liegen auf der Hand. Wenn Sie sich die Typen jedoch genauer ansehen, werden Sie feststellen, dass die Kosten den Nutzen übersteigen.

Konstruktor


In Kapitel 13 haben wir mit Fabriken gearbeitet - Funktionen, die Funktionen zurückgeben. Jetzt können wir mit Konstruktoren etwas Ähnliches tun - Funktionen, die Objekte zurückgeben, die Funktionen enthalten.

Beginnen wir mit der Erstellung von counter_constructor, ähnlich dem Zählergenerator. Es gibt zwei Methoden: Auf und Ab:

function counter_constructor() { let counter = 0; function up() { counter += 1; return counter; } function down() { counter -= 1; return counter; } return Object.freeze({ up, down }); } 

Das zurückgegebene Objekt wird eingefroren. Es kann nicht beschädigt oder beschädigt werden. Das Objekt hat einen Zustand. Der variable Zähler ist eine private Eigenschaft des Objekts. Sie können nur über Methoden darauf zugreifen. Und das brauchen wir nicht zu benutzen.

Dies ist ein sehr wichtiger Umstand. Die Objektschnittstelle besteht ausschließlich aus Methoden. Er hat eine sehr starke Schale. Wir bekommen die beste Kapselung. Es gibt keinen direkten Zugriff auf Daten. Dies ist ein sehr hochwertiger modularer Aufbau.

Ein Konstruktor ist eine Funktion, die ein Objekt zurückgibt. Die Parameter und Konstruktorvariablen werden zu privaten Eigenschaften des Objekts. Es hat keine öffentlichen Eigenschaften, die aus Daten bestehen. Interne Funktionen werden zu Objektmethoden. Sie verwandeln Eigenschaften in geschlossene. Methoden, die in ein eingefrorenes Objekt fallen, sind offen.

Methoden müssen Transaktionen implementieren. Nehmen wir zum Beispiel an, wir haben ein Personenobjekt. Möglicherweise müssen Sie die Adresse der Person ändern, deren Daten darin gespeichert sind. Dazu benötigen Sie keine separaten Funktionen zum Ändern jedes einzelnen Adresselements. Wir benötigen eine Methode, die ein Objektliteral empfängt und alle Teile der Adresse beschreiben kann, die geändert werden müssen.

Eine der brillanten Ideen in JavaScript ist das Objektliteral. Dies ist eine nette und ausdrucksstarke Syntax zum Clustering von Informationen. Durch das Erstellen von Methoden, die Datenobjekte verbrauchen und erstellen, können Sie die Anzahl der Methoden reduzieren und dadurch die Integrität des Objekts erhöhen.

Es stellt sich heraus, dass wir zwei Arten von Objekten haben.

  • Harte Objekte enthalten nur Methoden. Diese Objekte schützen die Integrität der im Abschluss enthaltenen Daten. Sie versorgen uns mit Polymorphismus und Einkapselung.
  • Soft Data-Objekte enthalten nur Daten. Sie haben kein Verhalten. Dies ist nur eine praktische Sammlung, mit der Funktionen arbeiten können.

Es wird angenommen, dass OOP zunächst Verfahren zu Datensätzen in der Kobol-Sprache hinzufügte, um so ein Verhalten sicherzustellen. Ich glaube, dass die Kombination von Datenmethoden und Eigenschaften ein wichtiger Schritt nach vorne war, aber nicht der letzte Schritt sein sollte.

Wenn das harte Objekt in eine Zeichenfolge konvertiert werden muss, muss die toJSON-Methode aktiviert sein. Andernfalls sieht JSON.stringify es als leeres Objekt an und ignoriert Methoden und versteckte Daten (siehe Kapitel 22).

Konstruktoroptionen


Einmal habe ich einen Konstruktor erstellt, der zehn Argumente akzeptiert. Es war sehr schwierig zu verwenden, da sich niemand an die Reihenfolge der Argumente erinnern konnte. Später wurde bemerkt, dass niemand das zweite Argument verwendete. Ich wollte es aus der Liste der Parameter entfernen, aber das würde den gesamten bereits entwickelten Code beschädigen.

Wenn ich umsichtig wäre, hätte ich einen Konstruktor, der ein Objekt als Parameter verwendet. Es stammt normalerweise aus einem Objektliteral, kann aber auch aus anderen Quellen stammen, z. B. aus JSON-Inhalten.

Dies würde viele Vorteile bieten.

  • Schlüsselzeilen geben dem Code ein dokumentiertes Aussehen. Der Code ist einfacher zu lesen, da er Ihnen sagt, was jedes Argument für den Aufrufer ist.
  • Argumente können in beliebiger Reihenfolge angeordnet werden.
  • In Zukunft können Sie neue Argumente hinzufügen, ohne den vorhandenen Code zu beschädigen.
  • Irrelevante Parameter können ignoriert werden.

Am häufigsten wird ein Parameter verwendet, um eine private Eigenschaft zu initialisieren. Dies geschieht wie folgt:

 function my_little_constructor(spec) { let { name, mana_cost, colors, type, supertypes, types, subtypes, text, flavor, power, toughness, loyalty, timeshifted, hand, life } = spec; 

Dieser Code erstellt und initialisiert 15 private Variablen unter Verwendung von Eigenschaften mit denselben Namen aus spec. Wenn spec keine entsprechende Eigenschaft hat, wird eine neue Variable initialisiert, der der undefinierte Wert zugewiesen wird. Auf diese Weise können Sie alle fehlenden Werte mit Standardwerten füllen.

Zusammensetzung


Die lebendige Ausdruckskraft und Effektivität von JavaScript ermöglicht es Ihnen, Programme im klassischen Paradigma zu erstellen, obwohl diese Sprache nicht für die klassischen gilt. JavaScript ermöglicht auch Verbesserungen. Wir können mit einer funktionalen Zusammensetzung arbeiten. Anstatt also ausnahmsweise etwas hinzuzufügen, können Sie ein wenig von diesem und jenem bekommen. Der Konstruktor hat das folgende allgemeine Erscheinungsbild:

 function my_little_constructor(spec) { let {} = spec; const _ = other_constructor(spec); const  = function () { //   spec, , _,  }; return Object.freeze({ , _. }); } 

Ihr Konstruktor kann beliebig viele andere Konstruktoren aufrufen, um Zugriff auf die Statusverwaltung und das von ihnen bereitgestellte Verhalten zu erhalten. Sie können ihm sogar genau das gleiche Spezifikationsobjekt übergeben. Durch die Dokumentation der Spezifikationsparameter listen wir die Eigenschaften auf, die von my_little_constructor benötigt werden, und die Eigenschaften, die von anderen Konstruktoren benötigt werden.

Manchmal können Sie die resultierenden Methoden einfach einem eingefrorenen Objekt hinzufügen. In anderen Fällen haben wir neue Methoden, die die empfangenen Methoden aufrufen. Dies stellt sicher, dass Code ähnlich wie bei der Vererbung wiederverwendet wird, jedoch ohne starken Zusammenhalt. Ein Funktionsaufruf ist das ursprüngliche Schema für die Wiederverwendung von Code, und es wurde nichts Besseres erfunden.

Größe


Bei diesem Ansatz zum Erstellen eines Objekts ist mehr Speicher erforderlich als bei der Verwendung von Prototypen, da jedes starre Objekt alle Methoden des Objekts enthält und das Prototypobjekt eine Verknüpfung zu dem Prototyp enthält, der die Methoden enthält. Ist der Unterschied im Speicherverbrauch signifikant? Wenn wir den Unterschied mit den neuesten Errungenschaften bei der Erhöhung der Speicherkapazität vergleichen, können wir sagen: Nein. Wir sind es gewohnt, Speicher in Kilobyte zu lesen. Und jetzt betrachten wir es in Gigabyte. Vor diesem Hintergrund ist der Unterschied überhaupt nicht zu spüren.

Der Unterschied kann durch Verbesserung der Modularität verringert werden. Durch die Betonung auf Transaktionen und nicht auf Eigenschaften können Sie die Anzahl der Methoden reduzieren und gleichzeitig die Konnektivität verbessern.

Das klassische Modell zeichnet sich durch Einheitlichkeit aus. Jedes Objekt muss eine Instanz einer Klasse sein. JavaScript hebt diese Einschränkungen auf. Nicht alle Objekte müssen solch strengen Regeln entsprechen.

Zum Beispiel glaube ich, dass es keinen Sinn macht, dass Punkte notwendigerweise starre Objekte mit Methoden sind. Ein Punkt kann ein einfacher Container für zwei oder drei Zahlen sein. Punkte werden an Funktionen übergeben, die projiziert oder interpoliert werden können, oder an etwas anderes, das mit Punkten ausgeführt werden kann. Dies kann viel produktiver sein als Unterklassenpunkte, um ihnen ein besonderes Verhalten zu verleihen. Lass die Funktionen funktionieren.

»Weitere Informationen zum Buch finden Sie auf der Website des Herausgebers
» Inhalt
» Auszug

25% Rabatt auf Gutschein für Händler - JavaScript

Nach Bezahlung der Papierversion des Buches wird ein elektronisches Buch per E-Mail verschickt.

Source: https://habr.com/ru/post/de455698/


All Articles