Reflexion und Proxy in Front-End-JavaScript

Reflexion und Proxy in Front-End-JavaScript

1. Was ist Reflexion?

Das Konzept der Reflexion existiert in vielen Programmiersprachen, beispielsweise Java und C# .

Bei der objektorientierten Programmierung werden in der Regel zuerst Klassen und Methoden definiert und dann Objekte erstellt, um Methoden explizit aufzurufen, wie im folgenden Beispiel:

öffentliche Klasse Benutzer{
   privater String-Name;
   privates Datum Geburtstag;
       //....
   public int berechneAlterNachGeburtstag(){
            // .....
   }
}
// Benutzer aufrufen u = neuer Benutzer("jack", neues Datum());
u.calculateAgeByBirthday();


Wir sind mit der obigen Aufrufmethode vertraut. Wenn Sie jedoch abstrakte Frameworks schreiben möchten (die Frameworks müssen mit geschäftsdefinierten Klassen zusammenarbeiten), wird Reflektion verwendet, um Mitgliedsvariablen dynamisch abzurufen oder Methoden aufzurufen, da Sie die Mitglieder und Methoden der Geschäftsklassen nicht kennen.

Im folgenden Beispiel verwenden wir Reflexion, um JSON in ein Java-Objekt zu konvertieren.

öffentliche statische Klasse Benutzer {
 privater String-Name;
 öffentliche Zeichenfolge getName() {
    Rückgabename;
 }
   öffentliche void setName(String name) {
     dieser.name = Name;
   }
}

// Verwenden Sie Reflektion, um die Objekt-Setter-Methode aufzurufen.
öffentliche statische <T> T füllen (Klasse <T> Benutzerklasse, Map <String, Objekt> json) wirft Ausnahme {
        Feld[] Felder = userClass.getDeclaredFields();
        T Benutzer = Benutzerklasse.neueInstanz();
        für (Feld Feld : Felder) {
            // Den ersten Buchstaben groß schreiben String name = field.getName();
            char[] arr = name.toCharArray();
            arr[0] = Character.toUpperCase(arr[0]);
            System.out.println(neuer String(arr));
            Methode method = userClass.getDeclaredMethod("set" + new String(arr), field.getType());
            Objekt returnValue = method.invoke(Benutzer, json.get(Name));
        }
        Benutzer zurückgeben;
}

2. Reflektieren in JavaScript

JavaScript bietet in ES6 ein integriertes Reflexionsobjekt Reflect , aber die Reflexion in JavaScript unterscheidet sich von der Java-Reflexion. Schauen Sie sich zunächst die 13 statischen Methoden an, die Reflect bereitstellt.

  • Reflect.apply(target, thisArg, args)
  • Reflect.construct(target, args)
  • Reflect.get(target, name, receiver)
  • Reflect.set(target, name, value, receiver)
  • Reflect.defineProperty(target, name, desc)
  • Reflect.deleteProperty(target, name)
  • Reflect.has(target, name)
  • Reflect.ownKeys(target)
  • Reflect.isExtensible(target)
  • Reflect.preventExtensions(target)
  • Reflect.getOwnPropertyDescriptor(target, name)
  • Reflect.getPrototypeOf(target)
  • Reflect.setPrototypeOf(target, prototype)

2.1 Reflect.get(Ziel, Name, Empfänger)

Die Methode Reflect.get sucht die Eigenschaft name des Zielobjekts und gibt sie zurück. Wenn keine solche Eigenschaft vorhanden ist, wird undefined zurückgegeben.

const obj = {
  Name: 'Jack',
  Alter: 12,
  erhalte Benutzerinformationen () {
    returniere diesen Namen + „Alter ist“ + dieses Alter;
  }
}

Reflect.get(obj, 'name') // Buchse
Reflect.get(obj, 'Alter') // 12
Reflect.get(obj, 'userInfo') // Jack ist 12 Jahre alt

// Wird beim Aufruf der Funktion userInfo() der Receiver-Parameter übergeben, so bezieht sich dieser auf das Empfängerobjekt.
const EmpfängerObj = {
  Name: 'Xiaoming',
  Alter: 22
};

Reflect.get(obj, 'userInfo', receiverObj) // Xiaoming ist 22 Jahre alt

2.2 Reflect.set(Ziel, Name, Wert, Empfänger)

const obj = {

  Name: 'Jack',
  Alter: 12,
  setze updateAge(Wert) {
    gib this.age = Wert zurück;
  },
}
Reflect.set(Objekt, 'Alter', 22);
obj.age // 22

// Wird beim Aufruf der Funktion updateAge() der Receiver-Parameter übergeben, so bezieht sich dieser auf das Receiver-Objekt.
const EmpfängerObj = {
  Alter: 0
};

Reflect.set(Objekt, 'Aktualisierungsalter', 10, Empfängerobjekt) // 
obj.age // 22
Empfängerobjekt.Alter // 10

2.3 Reflect.has(Objekt, Name)

Reflect.has entspricht dem in Operator in name in obj .

const obj = {
  Name: 'Jack',
}
obj im Namen // wahr
Reflect.has(Objekt, 'Name') // wahr

2.4 Reflect.deleteProperty(Objekt, Name)

Reflect.deleteProperty entspricht delete obj[name] und wird zum Löschen der Eigenschaften eines Objekts verwendet. Wenn der Löschvorgang erfolgreich ist oder das gelöschte Attribut nicht existiert, wird true zurückgegeben; wenn der Löschvorgang fehlschlägt und das gelöschte Attribut noch existiert, wird „false“ zurückgegeben.

const obj = {
  Name: 'Jack',
}
Objektnamen löschen 
Reflect.deleteProperty(Objekt, 'Name')


2.5 Reflect.construct(Ziel, Argumente)

Die Methode Reflect.construct entspricht new target(...args) .

Funktion Benutzer(Name){
  dieser.name = Name;
}
const Benutzer = neuer Benutzer('Jack');
Reflect.construct(Benutzer, ['jack']);
Reflect.getPrototypeOf(obj)
Die Methode Reflect.getPrototypeOf wird verwendet, um die __proto__-Eigenschaft eines Objekts zu lesen.

2.6 Reflect.setPrototypeOf(Objekt, neuesProto)

Mit Reflect.setPrototypeOf wird der prototype des Zielobjekts festgelegt. Gibt einen Booleschen Wert zurück, der angibt, ob die Einstellung erfolgreich war.

const obj = {
  Name: 'Jack',
}
Reflect.setPrototypeOf(obj, Array.prototype);
obj.länge // 0

2.7 Reflect.apply(Funktion, diesesArg, Argumente)

Die Methode Reflect.apply entspricht Function.prototype.apply.call(func, thisArg, args) und wird verwendet, um eine bestimmte Funktion nach dem Binden this Objekts auszuführen.

Konstante Nums = [1,2,3,4,5];
const min = Math.max.apply(Math, nums);
// Aufgerufen über Reflect.apply const min = Reflect.apply(Math.min, Math, nums);

2.8 Reflect.defineProperty(Ziel, Eigenschaftsschlüssel, Attribute)

Reflect.defineProperty entspricht Object.defineProperty und wird zum Definieren von Eigenschaften für Objekte verwendet.

const obj = {};
Object.defineProperty(obj, 'Eigenschaft', {
  Wert: 0,
  beschreibbar: false
});

Reflect.defineProperty(Objekt, 'Eigenschaft', {
  Wert: 0,
  beschreibbar: false
});

2.9 Reflect.getOwnPropertyDescriptor(Ziel, Eigenschaftsschlüssel)

Ruft ein Beschreibungsobjekt für die angegebene Eigenschaft ab.

2.10 Reflect.isExtensible (Ziel)

Gibt einen Booleschen Wert zurück, der angibt, ob das aktuelle Objekt erweiterbar ist.

2.11 Reflect.preventExtensions(Ziel)

Wird verwendet, um ein Objekt nicht erweiterbar zu machen. Es wird ein Boolescher Wert zurückgegeben, der angibt, ob der Vorgang erfolgreich war.

2.13 Reflect.ownKeys (Ziel)

Reflect.ownKeys wird verwendet, um alle Eigenschaften eines Objekts zurückzugeben.

const obj = {
  Name: 'Jack',
  Alter: 12,
  erhalte Benutzerinformationen () {
    returniere diesen Namen + „Alter ist“ + dieses Alter;
  }
}
Objekt.getOwnPropertyNames(obj)
Reflect.ownKeys(obj) // ['Name', 'Alter', 'Benutzerinfo']

3. Proxy in JavaScript

Proxys sind beim Programmieren sehr nützlich. Sie können vor dem Zielobjekt eine „Abfangebene“ hinzufügen, um eine gemeinsame Logik zu implementieren.

Proxy -KonstruktorProxy (Ziel, Proxy ) Parameter:

  • target : Das Zielobjekt des Proxys, das jeder beliebige Objekttyp sein kann, einschließlich integrierter Arrays, Funktionen und Proxy-Objekte.
  • handler : Dies ist ein Objekt, dessen Eigenschaften die Verarbeitungsfunktion bereitstellen, wenn bestimmte Vorgänge auftreten.
const user = {name: 'hallo'}
const proxy = neuer Proxy(Benutzer, {
  get: function(target, property) { // Wird beim Lesen der Eigenschaft ausgelöst return 'hi';
  }
});
Proxy.name // "hallo"

3.1 Im Proxy unterstützte Abfangvorgänge

  • handler.get(target, property, receiver)
  • handler.set(target, property, value, receiver)
  • handler.has(target, property)
  • handler.defineProperty(target, property, descriptor)
  • handler.deleteProperty(target, property)
  • handler.getOwnPropertyDescriptor(target, prop)
  • handler.getPrototypeOf(target)
  • handler.setPrototypeOf(target, prototype)
  • handler.isExtensible(target)
  • handler.ownKeys(target)
  • handler.preventExtensions(target)
  • handler.apply(target, thisArg, argumentsList)
  • handler.construct(target, argumentsList, newTarget)

3.2 get()

Es wird verwendet, um den Lesevorgang eines bestimmten Attributs abzufangen. Es kann drei Parameter akzeptieren, nämlich das Zielobjekt, den Attributnamen und proxy Instanz selbst. Der letzte Parameter ist optional.

const Benutzer = {
  Name: 'Jack'
}
//Gibt nur dann einen Wert zurück, wenn das Attribut vorhanden ist, andernfalls wird eine Ausnahme ausgelöst.
const proxy = neuer Proxy(Benutzer, {
  get: Funktion(Ziel, Eigenschaft) {
    if (!(Eigenschaft im Ziel)) {
       throw new ReferenceError(`${property} existiert nicht.`);
    }
    Ziel [Eigenschaft] zurückgeben;
  }
});
Proxy.Name // Buchse
proxy.age // ReferenceError: Alter existiert nicht.


Wir können einige allgemeine Proxy-Objekte definieren und diese dann an untergeordnete Objekte erben lassen.

//Gibt nur dann einen Wert zurück, wenn das Attribut vorhanden ist, andernfalls wird eine Ausnahme ausgelöst.
const proxy = neuer Proxy({}, {
  get: Funktion(Ziel, Eigenschaft) {
    if (!(Eigenschaft im Ziel)) {
       throw new ReferenceError(`${property} existiert nicht.`);
    }
    Ziel [Eigenschaft] zurückgeben;
  }
});
let obj = Objekt.erstellen(Proxy);
obj.name = "hallo"
obj.name // hallo
obj.age // ReferenceError: Alter existiert nicht.

3.3 einstellen()

Es wird verwendet, um die Zuweisungsoperation eines bestimmten Attributs abzufangen. Es kann vier Parameter akzeptieren, nämlich das Zielobjekt, den Attributnamen, den Attributwert und Proxy Instanz selbst. Der letzte Parameter ist optional.

// Prüfung der Länge des Zeichentyp-Attributs let sizeValidator = {
  set: Funktion(Ziel, Eigenschaft, Wert, Empfänger) {
    wenn (Typ des Wertes == 'Zeichenfolge' und Wert.Länge > 5) {
       throw new RangeError('Darf nicht länger als 5 Zeichen sein.');
    }
    Ziel[Eigenschaft] = Wert;
    gibt true zurück;
  }
};

const validator = neuer Proxy({}, sizeValidator);
let obj = Objekt.create(validator);
obj.name = '123456' // RangeError: Darf nicht länger als 5 Zeichen sein.
obj.age = 12 // 12

3.4 hat()

Wird verwendet, um den HasProperty Vorgang abzufangen, d. h. diese Methode wird wirksam, wenn bestimmt wird, ob ein Objekt eine bestimmte Eigenschaft hat. Wie beispielsweise der in Operator.

Es akzeptiert zwei Parameter, das Zielobjekt und den abzufragenden Attributnamen.

const handler = {
  hat (Ziel, Schlüssel) {
    wenn (Schlüssel[0] === '_') {
      gibt false zurück;
    }
    Eingabetaste im Ziel;
  }
};
var Ziel = { _prop: 'foo', prop: 'foo' };
var Proxy = neuer Proxy (Ziel, Handler);
'_prop' im Proxy // falsch

3.5 defineProperty()

defineProperty() fängt Object.defineProperty() ab.

3.6 deleteProperty()

Wird verwendet, um delete abzufangen. Wenn diese Methode einen Fehler auslöst oder false zurückgibt, kann das aktuelle Attribut nicht mit dem delete gelöscht werden.

3.7 getOwnPropertyDescriptor()

getOwnPropertyDescriptor() fängt Object.getOwnPropertyDescriptor() ab und gibt ein Eigenschaftsbeschreibungsobjekt oder undefined zurück.

3.8 getPrototypeOf()

Es wird hauptsächlich zum Abfangen und Erhalten des Objektprototyps verwendet. Der Abfangvorgang ist wie folgt:

  • Object.getPrototypeOf()
  • Reflect.getPrototypeOf()
  • __proto__
  • Object.prototype.isPrototypeOf()
  • instanceof
const obj = {};
const proto = {};
const handler = {
    getPrototypeOf(Ziel) {
        konsole.log(ziel === obj); // wahr
        konsole.log(dieser === handler); // wahr
        Prototyp zurückgeben;
    }
};

const p = neuer Proxy(Objekt, Handler);
console.log(Object.getPrototypeOf(p) === proto); // wahr

3.9 setPrototypeOf()

Wird hauptsächlich verwendet, um Object.setPrototypeOf() abzufangen.

const handlerReturnsFalse = {
    setzePrototyp von(Ziel, neuesProto) {
        gibt false zurück;
    }
};

const newProto = {}, Ziel = {};

const p1 = neuer Proxy (Ziel, Handler gibt Falsch zurück);
Object.setPrototypeOf(p1, newProto); // wirft einen TypeError
Reflect.setPrototypeOf(p1, newProto); // gibt false zurück

3.10 istErweiterbar()

Die Methode fängt die Operation Object.isExtensible() ab.

const p = neuer Proxy({}, {
  isExtensible: Funktion(Ziel) {
    console.log('aufgerufen');
    return true; //Sie können auch 1; usw. zurückgeben, um den Wert von true darzustellen}
});

console.log(Object.isExtensible(p)); // "aufgerufen"
                                     // WAHR

3.11 ownKeys()

Wird verwendet, um den Lesevorgang der eigenen Attribute des Objekts abzufangen. Im Einzelnen werden folgende Vorgänge abgefangen.

  • Object.getOwnPropertyNames()
  • Object.getOwnPropertySymbols()
  • Object.keys()
  • for...in einer Schleife.
const p = neuer Proxy({}, {
  ownKeys: Funktion(Ziel) {
    console.log('aufgerufen');
    zurückgeben ['a', 'b', 'c'];
  }
});

console.log(Object.getOwnPropertyNames(p)); // "aufgerufen"

3.12 preventExtensions()

Wird verwendet, um Object.preventExtensions() abzufangen. Diese Methode muss einen Booleschen Wert zurückgeben, andernfalls wird sie automatisch in einen Booleschen Wert umgewandelt.

Diese Methode unterliegt einer Einschränkung: proxy.preventExtensions kann nur dann true zurückgeben, wenn das Zielobjekt nicht erweiterbar ist (d. h., Object.isExtensible(proxy)為false ), andernfalls wird ein Fehler gemeldet.

const p = neuer Proxy({}, {
  preventExtensions: Funktion(Ziel) {
    console.log('aufgerufen');
    Objekt.preventExtensions(Ziel);
    gibt true zurück;
  }
});

console.log(Object.preventExtensions(p)); // "aufgerufen"
                                          // FALSCH

3.13 anwenden()

Die Apply-Methode fängt die folgenden Vorgänge ab.

  • proxy(...args)
  • Function.prototype.apply() und Function.prototype.call()
  • Reflect.apply()

Es akzeptiert drei Parameter: das Zielobjekt, das Kontextobjekt des Zielobjekts (dieses) und das Parameterarray des Zielobjekts.

const handler = {
  anwenden (Ziel, CTX, Argumente) {
    gibt Reflect.apply(...Argumente) zurück;
  }
};


Beispiel:

const Ziel = Funktion () { };
const handler = {
  anwenden: Funktion (Ziel, diesesArg, Argumentliste) {
    console.log('aufgerufen: ' + argumentsList.join(', '));
    returniere Argumentliste[0] + Argumentliste[1] + Argumentliste[2];
  }
};

const p = neuer Proxy (Ziel, Handler);
p(1,2,3) // "aufgerufen: 1, 2, 3" 6

3.14 Konstrukt()

Wird verwendet, um new Befehle abzufangen. So schreiben Sie das Abfangobjekt:

const handler = {
  Konstrukt (Ziel, Argumente, neues Ziel) {
    gib neues Ziel zurück (... Argumente);
  }
};

Diese Methode akzeptiert drei Parameter.

  • target : Zielobjekt.
  • args : Ein Array von Argumenten für den Konstruktor.
  • newTarget : Der Konstruktor, auf den der neue Befehl beim Erstellen eines Instanzobjekts einwirkt.

Hinweis: Die Methode muss ein Objekt zurückgeben und das Zielobjekt muss eine Funktion sein, andernfalls wird ein Fehler gemeldet.

const p = neuer Proxy(Funktion() {}, {
  Konstrukt: Funktion(Ziel, Argumentliste) {
    gebe 0 zurück;
  }
});

new p() // Der Rückgabewert ist kein Objekt, es wird ein Fehler gemeldet const p = new Proxy({}, {
  Konstrukt: Funktion(Ziel, Argumentliste) {
    zurückkehren {};
  }
});
new p() //Das Zielobjekt ist keine Funktion, Fehler

4. Beobachtermuster

Observer ist ein sehr verbreitetes Muster, das so definiert ist, dass bei einer Zustandsänderung eines Objekts alle davon abhängigen Objekte benachrichtigt und automatisch aktualisiert werden.

Wir verwenden Proxy , um ein Beispiel zu implementieren, bei dem die Beobachtungsfunktion automatisch ausgeführt wird, wenn sich der Zustand des beobachteten Objekts ändert.

Beobachterfunktion, umschließt das Beobachtungsziel und fügt die Beobachtungsfunktion hinzu.

  • observable umschließt das beobachtete Ziel und gibt ein Proxy Objekt zurück.
  • observe fügt der Warteschlange eine Beobachtungsfunktion hinzu.
const queuedObservers = neues Set();

const observe = fn => queuedObservers.add(fn);
const observable = obj => neuer Proxy(obj, {set});
//Bei einer Eigenschaftsänderung die Beobachtungsfunktion automatisch ausführen.
Funktionssatz (Ziel, Schlüssel, Wert, Empfänger) {
  const Ergebnis = Reflect.set(Ziel, Schlüssel, Wert, Empfänger);
  queuedObservers.forEach(Beobachter => Beobachter());
  Ergebnis zurückgeben;
}

Beispiel:

const Benutzer = beobachtbar({
  Name: 'Jack',
  Alter: 20
});

Funktion Benutzerinfo() {
  console.log(`${Benutzername}, ${Benutzeralter}`)
}

beobachten(Benutzerinfo);
Benutzername = "Xiaoming"; // Xiaoming, 20

Damit ist dieser Artikel über Reflexion und Proxy in Front-End JavaScript abgeschlossen. Weitere relevante Inhalte zu JavaScript-Reflexion und Proxy finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Ein Artikel zum Verständnis der Verwendung von Proxys in JavaScript
  • JavaScript-Entwurfsmuster, Proxy-Muster lernen
  • JavaScript-Designmuster – Prinzipien und Anwendungsbeispielanalyse des Proxy-Musters
  • JavaScript fügt Ereignis-Listener zur Ereignisdelegierung in Batches hinzu. Detaillierter Prozess
  • Tiefgreifendes Verständnis des Ereignisausführungsmechanismus von JavaScript
  • Eine kurze Analyse von Event Bubbling und Event Capture in js
  • Fallstudie zu JavaScript-Ereignisschleifen
  • Detaillierte Analyse von Javascript-Datenproxys und Ereignissen

<<:  So trennen Sie statischen und dynamischen Status durch die Kombination von Apache und Tomcat

>>:  MySQL-Primärschlüssel-Benennungsstrategie im Zusammenhang

Artikel empfehlen

Dieser Artikel zeigt Ihnen, wie Sie Vue 3.0 responsive verwenden

Inhaltsverzeichnis Anwendungsfälle Reaktive API-b...

Detaillierte Erklärung des Linx awk-Einführungstutorials

Awk ist eine Anwendung zur Verarbeitung von Textd...

Detaillierte Erläuterung des Anwendungsbeispiels für den JQuery-Tag-Selektor

In diesem Artikelbeispiel wird der spezifische Co...

So deklarieren Sie einen Cursor in MySQL

So deklarieren Sie einen Cursor in MySQL: 1. Vari...

So greifen Sie in Docker auf den lokalen Computer (Hostcomputer) zu

Frage Wie greife ich in Docker auf die lokale Dat...

Detaillierte Erklärung der Überwachungseigenschaften von Vue

Inhaltsverzeichnis Vue-Monitoreigenschaften Was i...

Analyse des Prozesses zum Erstellen eines LAN-Servers basierend auf http.server

Ich weiß nicht, ob Sie schon einmal in eine solch...

Beispielcode für HTML-Formularkomponente

HTML-Formulare werden verwendet, um verschiedene ...