Heim  >  Artikel  >  Web-Frontend  >  Einführung in ein einfaches JavaScript-Klassen-Framework_Grundkenntnisse

Einführung in ein einfaches JavaScript-Klassen-Framework_Grundkenntnisse

WBOY
WBOYOriginal
2016-05-16 15:52:571102Durchsuche

Als ich das in Arbeit befindliche JavaScript-Buch schrieb, habe ich viel Zeit mit dem JavaScript-Vererbungssystem verbracht und dabei verschiedene Lösungen zur Simulation der klassischen Klassenvererbung studiert. Unter diesen technischen Lösungen bewundere ich die Implementierung von base2 und Prototype am meisten.

Aus diesen Lösungen sollte ein Framework mit seiner ideologischen Konnotation abgeleitet werden. Das Framework muss einfach, wiederverwendbar, leicht verständlich und unabhängig von Abhängigkeiten sein. Hier sind Anwendungsbeispiele:

var Person = Class. extend ( {
 init: function (isDancing ) {
  this. dancing = isDancing;
 },
 dance: function ( ) {
  return this. dancing;
 }
} );
var Ninja = Person.extend({
 init: function(){
  this._super( false );
 },
 dance: function(){
  // Call the inherited version of dance()
  return this._super();
 },
 swingSword: function(){
  return true;
 }
});
var p = new Person(true);
p.dance(); // => true
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class

Es gibt ein paar Dinge zu beachten:

  • Der Konstruktor muss einfach sein (implementiert durch die Init-Funktion),
  • Die neu definierte Analogie muss von der vorhandenen Klasse erben,
  • Alle „Klassen“ erben von der Vorgängerklasse: Class. Wenn Sie also eine brandneue Klasse erstellen möchten, muss die Klasse eine Unterklasse von Class sein,
  • Der schwierigste Punkt: Auf die überschriebene Methode der übergeordneten Klasse muss zugegriffen werden können (über den Konfigurationskontext).
  • Im obigen Beispiel können Sie feststellen, dass die Methoden init() und dance() der übergeordneten Klasse Person über this._super() aufgerufen werden.

Sehr zufrieden mit den Ergebnissen: Die Klassendefinition wurde strukturiert, die Einzelvererbung wurde beibehalten und es konnten Superklassenmethoden aufgerufen werden.

Einfache Klassenerstellung und -vererbung

Das Folgende ist die Implementierung (leicht zu lesen und mit Kommentaren), etwa 25 Zeilen. Vorschläge sind willkommen und willkommen.

/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
( function ( ) {
 var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
 // The base Class implementation (does nothing)
 this.Class = function(){};
  
 // Create a new Class that inherits from this class
 Class.extend = function(prop) {
  var _super = this.prototype;
   
  // Instantiate a base class (but only create the instance,
  // don't run the init constructor)
  initializing = true;
  var prototype = new this();
  initializing = false;
   
  // Copy the properties over onto the new prototype
  for (var name in prop) {
   // Check if we're overwriting an existing function
   prototype[name] = typeof prop[name] == "function" &&
    typeof _super[name] == "function" && fnTest.test(prop[name]) ?
    (function(name, fn){
     return function() {
      var tmp = this._super;
       
      // Add a new ._super() method that is the same method
      // but on the super-class
      this._super = _super[name];
       
      // The method only need to be bound temporarily, so we
      // remove it when we're done executing
      var ret = fn.apply(this, arguments);    
      this._super = tmp;
       
      return ret;
     };
    })(name, prop[name]) :
    prop[name];
  }
   
  // The dummy class constructor
  function Class() {
   // All construction is actually done in the init method
   if ( !initializing && this.init )
    this.init.apply(this, arguments);
  }
   
  // Populate our constructed prototype object
  Class.prototype = prototype;
   
  // Enforce the constructor to be what we expect
  Class.prototype.constructor = Class;
  // And make this class extendable
  Class.extend = arguments.callee;
   
  return Class;
 };
})();

Davon sind „Initialisieren/Init nicht aufrufen“ und „_super-Methode erstellen“ die schwierigsten. Als nächstes werde ich eine kurze Einführung dazu geben, damit jeder den Implementierungsmechanismus besser verstehen kann.

Initialisierung

Um die Vererbungsmethode des Funktionsprototyps zu veranschaulichen, schauen wir uns zunächst den traditionellen Implementierungsprozess an, der darin besteht, das Prototypattribut der Unterklasse auf eine Instanz der übergeordneten Klasse zu verweisen. Wie unten gezeigt:


function Person ( ) { }
function Ninja ( ) { }
Ninja. prototype = new Person ( );
// Allows for instanceof to work:
(new Ninja()) instanceof Person

Die Herausforderung hierbei besteht jedoch darin, dass wir nur die Wirkung von „instatnceOf“ erzielen möchten, ohne die Konsequenzen der Instanziierung einer Person und des Aufrufs ihres Konstruktors. Um dies zu verhindern, legen Sie im Code einen bool-Parameter fest, dessen Wert nur dann wahr ist, wenn die übergeordnete Klasse instanziiert und für die Prototypeigenschaft der untergeordneten Klasse konfiguriert wird. Der Zweck dieser Verarbeitung besteht darin, den Unterschied zwischen dem Aufruf des Konstruktors während der echten Instanziierung und der Designvererbung und dem anschließenden Aufruf der Init-Methode während der echten Instanziierung zu unterscheiden:

if ( !initializing )
 this.init.apply(this, arguments);

Es lohnt sich, besondere Aufmerksamkeit darauf zu richten, da in der Init-Funktion möglicherweise recht ressourcenintensiver Code ausgeführt wird (z. B. das Herstellen einer Verbindung zum Server, das Erstellen von DOM-Elementen usw. kann niemand vorhersagen), sodass dies unbedingt erforderlich ist einen Unterschied machen.

Super Methode

Bei der Verwendung der Vererbung besteht die häufigste Anforderung darin, dass die Unterklasse auf die überschriebenen Methoden der Oberklasse zugreifen kann. In dieser Implementierung besteht die endgültige Lösung darin, eine temporäre Methode (._super) bereitzustellen, die auf die Methode der Oberklasse verweist und auf die nur in der Methode der Unterklasse zugegriffen werden kann.

var Person = Class. extend ( {
 init: function (isDancing ) {
  this. dancing = isDancing;
 }
} );
var Ninja = Person.extend({
 init: function(){
  this._super( false );
 }
});
var p = new Person(true);
p.dancing; // => true
var n = new Ninja();
n.dancing; // => false


Die Implementierung dieser Funktionalität erfordert mehrere Schritte. Zuerst verwenden wir „extend“, um die grundlegende Person-Instanz (Klasseninstanz, deren Konstruktionsprozess wir oben erwähnt haben) mit dem Literalobjekt (Funktionsparameter von Person.extend()) zusammenzuführen. Während des Zusammenführungsprozesses wurde eine einfache Prüfung durchgeführt: Überprüfen Sie zunächst, ob das zusammenzuführende Attribut eine Funktion ist. Wenn ja, prüfen Sie dann, ob das zu überschreibende Oberklassenattribut ebenfalls eine Funktion ist. Wenn beide Prüfungen zutreffen, müssen Sie eine _super-Methode für diese Eigenschaft vorbereiten.

Beachten Sie, dass hier ein anonymer Abschluss (der ein Funktionsobjekt zurückgibt) erstellt wird, um die hinzugefügte Supermethode zu kapseln. Aufgrund der Notwendigkeit, die laufende Umgebung aufrechtzuerhalten, sollten wir die alte Datei this._super (unabhängig davon, ob sie vorhanden ist oder nicht) speichern, um sie nach der Ausführung der Funktion zurückzusetzen. Dies hilft in Fällen, in denen es denselben Namen gibt (nicht gewünscht). versehentlich den Objektzeiger verlieren) Unvorhersehbare Probleme.

Erstellen Sie dann eine neue _super-Methode, die nur auf die überschriebene Methode in der Superklasse verweist. Gott sei Dank besteht keine Notwendigkeit, Änderungen an _super vorzunehmen oder den Bereich zu ändern, da sich die Ausführungsumgebung der Funktion automatisch mit dem Funktionsaufrufobjekt ändert (der Zeiger zeigt auf die Superklasse).

Zum Schluss wird die Methode des Literalobjekts aufgerufen. This._super() kann während der Ausführung der Methode verwendet werden. Nach der Ausführung der Methode wird das Attribut _super auf seinen ursprünglichen Zustand zurückgesetzt und die Funktion wird anschließend beendet.


Es gibt viele Möglichkeiten, den gleichen Effekt zu erzielen (ich habe schon einmal gesehen, wie super an sich selbst gebunden wird und dann mit arguments.callee darauf zugegriffen wird), aber ich bin der Meinung, dass diese Methode die Eigenschaften von Benutzerfreundlichkeit und Einfachheit am besten widerspiegelt.

Unter den vielen auf JavaScript-Prototypen basierenden Arbeiten, die ich abgeschlossen habe, ist dies der einzige Implementierungsplan für die Klassenvererbung, den ich veröffentlicht habe, um ihn mit Ihnen zu teilen. Ich denke, dass prägnanter Code (einfach zu erlernen, leicht zu vererben, weniger Downloads) zur Diskussion gestellt werden muss. Daher ist dieser Implementierungsplan für Leute, die den Aufbau und die Vererbung von JavaScript-Klassen lernen, ein guter Anfang.

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn