Herkunft
Vor ein paar Tagen habe ich die Implementierung einiger beliebter Mini -MVVM -Frameworks (z. Die beliebten modernen MVVM-Frameworks eliminieren im Allgemeinen die bidirektionale Datenbindung von Daten (zweistreckige Datenbindung), was ein Verkaufsargument des Frameworks selbst ist (Ember.js scheint keine bidirektionale Bindung von Daten zu unterstützen) und die Implementierungsmethoden der bidirektionalen Datenbindung der einzelnen Framework sind nicht sehr konsistent. Beispielsweise verwendet Anguarjs eine schmutzige Überprüfung intern, während die Essenz der internen Implementierung von avalon.js darin besteht, Eigenschaftsbehörden festzulegen.
Wir beabsichtigen nicht, die spezifische Implementierung der bidirektionalen Datenbindung nach jedem Framework zu diskutieren. Wir werden nur über mehrere gängige Methoden zur Implementierung der bidirektionalen Datenbindung am Frontend sprechen und uns auf die technische Auswahl von avalon.js konzentrieren, um die bidirektionale Datenbindung zu implementieren.
Die konventionelle Implementierung von Zwei-Wege-Datenbindung
Lassen Sie uns zunächst darüber sprechen, was bidirektionale Datenbindung von Front-End-Daten ist. Einfach ausgedrückt ist es die Controller -Ebene des Frameworks (die Controller -Ebene hier ist ein allgemeiner Begriff, der als Middleware verstanden werden kann, das das Ansichtsverhalten steuert und die Modellschicht verbindet) und die UI -Anzeigeschicht (Ansichtsschicht), um einen bidirektionalen Datenkanal festzulegen. Wenn sich eine dieser beiden Ebenen ändert, führt die andere Ebene automatisch entsprechende Änderungen vor (oder scheint sofort zu sein).
Um diese Zwei-Wege-Datenbindungsbeziehung (der Korrelationsprozess zwischen der Reglerschicht und der Anzeigeschicht) zu verwirklichen, gibt es im Allgemeinen drei Möglichkeiten im Front-End.
1. Dirty Check
2. Beobachtungsmechanismus
3.. Kapitulelle Eigenschafts -Accessor umfassen
Schmutziger Scheck
Wir sagen, dass AngularJS (hier speziell auf die AngularJS 1.xx-Version bezieht, die keine AngularJS 2.xx-Version darstellt) eine technische Implementierung der Zwei-Wege-Datenbindung ist. Das allgemeine Prinzip ist, dass AngularJs eine Sequenz beibehält und alle Attribute platziert, die in dieser Sequenz überwacht werden müssen. Wenn bestimmte bestimmte Ereignisse auftreten (beachten Sie, dass dies nicht zeitlich festgelegt, sondern durch einige besondere Ereignisse ausgelöst wird), ruft AngularJS die $ Digest -Methode auf. Die Logik in dieser Methode besteht darin, alle Beobachter zu durchqueren, die überwachten Attribute zu vergleichen und zu vergleichen, ob sich der Attributwert vor und nach dem Methodenaufruf geändert hat. Wenn es sich ändert, wird der entsprechende Handler aufgerufen. Es gibt viele Artikel im Internet, die das Implementierungsprinzip der Zwei-Wege-Datenbindung von AngularJS wie diesem Artikel usw. analysieren.
Die Nachteile dieser Methode sind offensichtlich. Das Durchqueren und Training von Beobachtern ist sehr leistungsstark, insbesondere wenn die Anzahl der Überwachung einer einzelnen Seite eine Größenordnung erreicht.
Beobachtungsmechanismus
Der Blogger hatte einen nachgedruckten und übersetzten Artikel. Sobald es sich ändert, wird der entsprechende Handler ausgeführt.
Dies ist der perfekte Weg, um Attributdatenänderungen zu überwachen. Die native Unterstützung der Sprache (Browser) ist nichts besser als das. Das einzige Bedauern ist, dass die aktuelle Breite der Unterstützung nicht gut genug ist und vollständig gefördert werden muss.
Einkapselungseigenschafts -Accessor
Es gibt ein Konzept von magischen Methoden in PHP, wie die Methoden __Get () und __set () in PHP. JavaScript gibt es ein ähnliches Konzept, wird aber nicht als magische Methode, sondern als Accessor bezeichnet. Schauen wir uns einen Beispielcode an.
var data = {name: "erik", getName: function () {return this.name;}, setName: function (name) {this.name = name;}};Aus dem obigen Code können wir einen Blick auf den Sprung wie die Methoden GetName () und setName () in Daten erhalten. Wir können es einfach als Accessor (oder Accessor) von Data.name betrachten.
Tatsächlich darf der obige Code, wenn er strenger ist, nicht direkt auf die Eigenschaft von Data.name zugreifen. Alle Lesen und Schreiben in Data.Name müssen durch die Daten von Data.getName () und Data.SetName () weitergeleitet werden. Stellen Sie sich also vor, eine Eigenschaft erlaubt nicht direktes Lesen und Schreiben, sondern muss über den Accessor gelesen und geschrieben werden. Dann mache ich natürlich einige Extras, indem ich die Accessor -Methode der Eigenschaft umschreibe, z. B. die Überwachung der Eigenschaftswertänderung. Dies ist das Prinzip der Verwendung von Eigenschaftsbehörden, um eine Zwei-Wege-Datenbindung durchzuführen.
Natürlich hat diese Methode auch ihre Nachteile. Das herausragendste ist, dass jedes Mal, wenn eine Attributüberwachung hinzugefügt wird, eine entsprechende Accessor -Methode zu diesem Attribut hinzugefügt werden muss, ansonsten wird die Änderung dieses Attributs nicht erfasst.
Object.DefineProperty -Methode
Das Prinzip des inländischen MVVM -Frameworks avalon.js, das die bidirektionale Bindung von Daten implementiert, ist der Eigenschafts -Accessor. Aber natürlich wird es natürlich nicht so original sein wie der obige Beispielcode. Es verwendet das Standard-Eigenschaftsobjekt.DefineProperty-Methode, definiert in ECMascript 5.1 (ECMA-262). Als Reaktion auf die Inlandsmarktbedingungen unterstützen einige kein Objekt. DefineProperty. Browser mit niedrigem Niveau verwenden VBScript für eine perfekte Kompatibilität, im Gegensatz zu anderen MVVM-Frameworks, die nach und nach die Unterstützung für Low-End-Browser aufgegeben haben.
Lassen Sie uns zunächst das Objekt definieren. DefineProperty -Methode auf MDN.
Die Methode von Object.DefineProperty () definiert eine neue Eigenschaft direkt in einem Objekt oder ändern Sie eine vorhandene Eigenschaft in einem Objekt und gibt das Objekt zurück.
Die Bedeutung ist klar und das Objekt. DefineProperty -Methode bietet eine direkte Möglichkeit, Objekteigenschaften zu definieren oder vorhandene Objekteigenschaften zu ändern. Der Prototyp der Methode lautet wie folgt:
Object.DefineProperty (OBJ, Prop, Deskriptor)
In,
OBJ, Objekt zu modifizieren
Prop, mit geänderten Attributnamen
Deskriptor, die relevante Beschreibung der zu modifizierenden Attribute
Der Deskriptor verlangt, dass ein Objekt übergeben werden soll. Sein Standardwert lautet wie folgt
/*** @{Param} Deskriptor*/{Konfigurierbar: Falsch, aufgezählt: Falsch, beschreibbar: Falsch, Wert: NULL, SET: UNDEFINDIERT, GET: UNDEFINDIERT}Konfigurierbar, ob die Eigenschaft konfigurierbar ist. Zu den konfigurierbaren Bedeutungen gehören: ob das Attribut gelöscht werden kann, ob die beschreibbaren, aufzählbaren und konfigurierbaren Eigenschaften des Attributs geändert werden können.
Aufzählbar, ob das Attribut aufgezählt ist. Die Bedeutung von Aufzählung umfasst: ob sie für ... in und ob es über das Objekt erhalten werden kann. Keys () -Methode.
Beschreibbar, ob das Attribut neu abgeschrieben werden kann. Die Bedeutung des Umschreibens umfasst: ob das Attribut neu zugewiesen werden kann.
Wert, der Standardwert der Eigenschaft.
Set, ein Immobilien -Rewriter (vorerst das war es). Sobald das Attribut neu zugewiesen ist, wird diese Methode automatisch aufgerufen.
Holen Sie sich den Leser der Immobilie (vorerst das ist es). Sobald die Eigenschaft zugegriffen und gelesen wurde, wird diese Methode automatisch aufgerufen.
Hier ist ein Beispielcode,
var o = {}; Object.DefineProperty (o, 'name', {value: 'erik'}); console.log (Object.getownPropertyDescriptor (o, 'Name'); // Objekt {Wert: "Erik", beschreibbar: false, aufzählbar: false, konfigurierbar: false} Objekt.DefineProperty (o, 'ay', {value: 26, konfigurierbar: true, trueable: true}); console.log (o.age); // 26o.age = 18; console.log (o.age); // 18. Weil das Alterseigentum eine umschreiben konsole.log (Object.Keys (o)) ist; // []. Weder Name noch Alterseigenschaft ist ein aufzählbares Objekt. DeFineProperty (o, 'Sex', {value: 'männlich', beschreibbar: false}); o.sex = 'weiblich'; // Die Zuordnung ist hier tatsächlich eine ineffektive Konsole.log (O.Sex); // 'männlich'; lösche o.sex; // Falsch ist die Aktion der Eigenschaft löscher ebenfalls ungültigNach dem obigen Beispiel ist unter normalen Umständen die Verwendung von Objekt.definePropert () relativ einfach.
Es gibt jedoch noch eine Sache, die zusätzliche Aufmerksamkeit benötigt. Wenn das Object.DefineProperty () -Methode Eigenschaften festlegt, kann die Eigenschaft die Zubehörattribute (festgelegt und geteilt) und die Schreib- oder Wertattribute gleichzeitig nicht deklarieren. Wenn eine bestimmte Eigenschaft mit einem beschreibbaren oder Wertattribut festgelegt wird, kann diese Eigenschaft Get und Setzen nicht deklarieren und umgekehrt.
Denn wenn Object.defineProperty () eine Eigenschaft deklariert, sind mehr als zwei Arten von Zugriffskontrollen für dieselbe Eigenschaft nicht zulässig.
Beispielcode,
var o = {}, myName = 'erik'; Object.DefineProperty (o, 'name', {value: myName, set: function (name) {myName = name;}, get: function () {return myName;}});Der obige Code scheint in Ordnung zu sein, wird jedoch einen Fehler melden, wenn er tatsächlich ausgeführt wird, und der Fehler wird wie folgt gemeldet.
TypeError: Ungültige Eigenschaft. Eine Eigenschaft kann nicht beide Zubehör haben und beschreibbar sein oder einen Wert haben, #<Object>
Da das Namen des Namens hier das Wert -Attribut deklariert, werden die SET- und RET -Attribute gleichzeitig festgelegt, die beide zwei Lese- und Schreibsteuerungen für das Namensattribut angeben. Wenn die Wertfunktion hier nicht deklariert wird, aber das beschreibbare Merkmal deklariert wird, wird das Ergebnis das gleiche sein und ein Fehler wird gemeldet.