So implementieren Sie Property Hijacking mit JavaScript defineProperty

So implementieren Sie Property Hijacking mit JavaScript defineProperty

Vorwort

defineProperty ist der Kern von Vue, um Datenentführung zu erreichen. Dieser Artikel erklärt Schritt für Schritt, wie defineProperty die Datenentführung erreicht.

Tatsächlich bedienen wir Objekteigenschaften im Allgemeinen auf die Art und Weise, wie wir Eigenschaften hinzufügen oder ändern, und wir können Object.defineProperty verwenden.

lass obj = {};
// Allgemeiner Vorgang: Neues Attribut hinzufügen/ändern obj.a = 1;
// ist gleichbedeutend mit:
Objekt.defineProperty(o, "a", {
  Wert: 1,
  beschreibbar: true,
  konfigurierbar: true,
  aufzählbar: wahr
});

Natürlich würden wir es in normalen Beispielen nicht auf diese Weise spielen, da es zu langatmig wäre.

Mit „defineProperty“ können die Eigenschaften eines Objekts jedoch präziser hinzugefügt oder geändert werden.

Deskriptoren

Lassen Sie mich mit einem Eigennamen beginnen: Deskriptor.

Tatsächlich ist es der dritte Parameter von defineProperty, bei dem es sich um ein Objekt handelt. Dieses Objekt hat die folgenden Eigenschaften:

  • konfigurierbares Attribut: ob der Deskriptor geändert werden kann, d. h. ob andere Attribute des Deskriptors erneut geändert werden können
  • Aufzählbare Eigenschaft: ob die Eigenschaft aufzählbar ist, d. h. ob die Eigenschaft für
  • beschreibbares Attribut: ob der Attributwert geändert werden kann, d. h. ob obj.a = 1 auf diese Weise geändert werden kann
  • Wertattribut: der Wert des Attributs
  • Attribut abrufen: Dies ist eine Funktion. Wenn auf das Attribut zugegriffen wird, wird die Funktion automatisch aufgerufen und der Rückgabewert der Funktion ist der Wert des Attributs.
  • set property: ist eine Funktion. Wenn die Eigenschaft geändert wird, wird die Funktion automatisch aufgerufen. Die Funktion hat genau einen Parameter, nämlich den neuen Wert, der zugewiesen werden soll.

Beachten! ! !

  • Die Werteattribute, die Schreibattribute und die Get- und Set-Attribute im Deskriptor schließen sich gegenseitig aus. Es kann nur eines davon existieren.
  • Die Standardwerte anderer Eigenschaften sind alle falsch. Wenn Sie nicht möchten, dass sie falsch sind, denken Sie daran, sie zu konfigurieren. Ich werde nicht ins Detail gehen (hauptsächlich, weil ich sie nicht oft verwende).

Detaillierte Erklärung von get und set

  • Attribut abrufen: Dies ist eine Funktion. Wenn auf das Attribut zugegriffen wird, wird die Funktion automatisch aufgerufen und der Rückgabewert der Funktion ist der Wert des Attributs.
  • set property: ist eine Funktion. Wenn die Eigenschaft geändert wird, wird die Funktion automatisch aufgerufen. Die Funktion hat genau einen Parameter, nämlich den neuen Wert, der zugewiesen werden soll.

Wiederholen Sie dies dreimal still und merken Sie es sich.

Schreiben Sie zum besseren Verständnis ein Beispiel für „get“ und „set“.

Dieses Beispiel muss gemeistert werden. Wenn Sie es verstanden haben, werden Sie im Wesentlichen das Wesen des Datendiebstahls verstehen.

lass obj = {};

lass Wert = 1;
Objekt.defineProperty(obj, "b", {
  erhalten() {
    console.log("Attribut b lesen", Wert);
    Rückgabewert;
  },
  setze(neuerWert) {
    console.log("Eigenschaft b festlegen", neuerWert);
    Wert = neuerWert;
  }
});
// Löse die get-Funktion aus, der Rückgabewert von get ist der Attributwert // 1
Konsole.log(Objekt.b);
//Set-Funktion auslösen, der Wert wird 2, beachten! ! ! Zu diesem Zeitpunkt hat sich der Attributwert im Speicher nicht geändert obj.b = 2;
// Wenn Sie jedoch den Eigenschaftswert lesen möchten, wird die Get-Funktion zwangsläufig ausgelöst und der Eigenschaftswert ändert sich natürlich. Diese Idee ist wirklich gut console.log(obj.b);

Hier gibt es eine Falle: In get dürfen keine Leseoperationen vorkommen, sonst entsteht eine Endlosschleife. Wo also get set verwendet wird, wird immer eine Variable benötigt.

Der Wert der Variablen value ist hier also der Wert des Attributs. Wenn Sie das Attribut ändern möchten, ändern Sie einfach den Wert von value.

Ich denke, das reicht aus, um nach dem Verständnis dieses Beispiels die Essenz von Get und Set zu verstehen.

Entführung eines Attributs eines Objekts

Versuchen Sie, basierend auf dem vorherigen Beispiel, eine beliebige Eigenschaft des entführten Objekts zu schreiben.

Funktion observeKey(Objekt, Schlüssel) {
  let value = obj[Schlüssel];
  Objekt.defineProperty(Objekt, Schlüssel, {
    erhalten() {
      console.log("Eigenschaften lesen", Wert);
      Rückgabewert;
    },
    setze(neuerWert) {
      console.log("Eigenschaften festlegen", neuerWert);
      Wert = neuerWert;
    }
  });
}
lass obj = { a: 1 };
beobachteSchlüssel(Objekt, "a");
// Lesen Sie a, lösen Sie die Get-Funktion aus console.log(obj.a);
// Setze a, löse die Setzfunktion aus obj.a = 1;

Alle Eigenschaften eines Objekts kapern

Versuchen Sie, alle Eigenschaften des Objekts zu übernehmen

Tatsächlich handelt es sich um eine Durchquerung:

Funktion Obj beobachten(Objekt) {
  für (let key in obj) {
    // Die direkte Verwendung von obj.hasOwnProperty führt zu einem nicht standardmäßigen if (Object.prototype.hasOwnProperty.call(obj, key)) {
      observeKey(Objekt, Schlüssel);
    }
  }
  gibt Objekt zurück;
}
Funktion observeKey(Objekt, Schlüssel) {
  let value = obj[Schlüssel];
  Objekt.defineProperty(Objekt, Schlüssel, {
    erhalten() {
      console.log("Eigenschaften lesen", Wert);
      Rückgabewert;
    },
    setze(neuerWert) {
      console.log("Eigenschaften festlegen", neuerWert);
      Wert = neuerWert;
    }
  });
}

sei Objekt = { a: 1, b: 2 };
beobachteObjekt(Objekt);
konsole.log(obj);
// Lesen Sie a, lösen Sie die Get-Funktion aus console.log(obj.a);
// Setze a, löse die Setzfunktion aus obj.a = 1;

Alle Eigenschaften eines Objekts kapern - einschließlich des Eigenschaftswerts des Objekttyps

Das Obige weist einen Fehler auf: Wenn der Attributwert auch ein Objekt ist, kann der Attributwert nicht entführt werden, z. B. {a:1,c:{b:1}}

Einfach, Rekursion, füllen Sie es einfach aus.

Funktion Obj beobachten(Objekt) {
  // Parameterbeschränkungen hinzufügen, es können nur Objekte gekapert werden, was auch die Abbruchbedingung der Rekursion ist, wenn (typeof obj !== "object" || obj == null) {
    zurückkehren;
  }
  für (let key in obj) {
    // Die direkte Verwendung von obj.hasOwnProperty führt zu einem nicht standardmäßigen if (Object.prototype.hasOwnProperty.call(obj, key)) {
      observeKey(Objekt, Schlüssel);
      // Hier wird der Attributwert des Attributs gekapert. Wenn es kein Objekt ist, wird es direkt zurückgegeben, ohne Auswirkungen auf observeObj(obj[key]);
    }
  }
  gibt Objekt zurück;
}
Funktion observeKey(Objekt, Schlüssel) {
  let value = obj[Schlüssel];
  Objekt.defineProperty(Objekt, Schlüssel, {
    erhalten() {
      console.log("Eigenschaften lesen", Wert);
      Rückgabewert;
    },
    setze(neuerWert) {
      console.log("Eigenschaften festlegen", neuerWert);
      Wert = neuerWert;
    }
  });
}

lass obj = { a: 1, b: 2, c: { name: "c" } };
beobachteObjekt(Objekt);
konsole.log(obj);
// Lesen Sie a, lösen Sie die Get-Funktion aus console.log(obj.a);
// Setze a, löse die Setzfunktion aus obj.a = 1;
// Trigger-Set-Funktion obj.c.name = "d";

Beachten Sie, dass die Funktion „objectObj“ keine neuen Eigenschaften eines Objekts übernehmen kann, sondern nur die vorhandenen Eigenschaften des Objekts.

Die Nachteile von defineProperty

  • Objekt zum Hinzufügen von Attributen kann nicht überwacht werden
  • Objektlöschungsattribute können nicht überwacht werden
  • Array-Änderungen können nicht entführt werden

Natürlich können Array-Änderungen auch auf andere Weise überwacht werden, was durch die Entführung der Array-Änderungsmethode erreicht wird.

Die oben genannten Mängel sind auch der Grund, warum es in Vue $set/$delete gibt und warum Arrays nur mit bestimmten Methoden erkannt werden können.

sei Objekt = { a: 1, b: [1, 2] };
beobachteObjekt(Objekt);
// Neue Attribute hinzufügen obj.c = 3;
// Löst die Get-Funktion nicht aus console.log(obj.c);
// Löst die Set-Funktion nicht aus obj.b.push(3);

defineProperty kann auch Eigenschaften mounten

Tatsächlich handelt es sich um den Zugriff auf options.data.name, was als options.name abgekürzt werden kann, ein Fachbegriff, um die Attribute auf Daten an Optionen anzuhängen

Dies entspricht der Verwendung von defineProperty zum Hinzufügen neuer Eigenschaften zu Optionen:

// Mounten Sie zuerst ein einzelnes Attribut // options.data entspricht Quelle, options entspricht Ziel
Funktion ProxyKey(Ziel, Quelle, Schlüssel) {
  Object.defineProperty(Ziel, Schlüssel, {
    // Hier ist source[key] gleichbedeutend mit dem Variablenwert, daher ist das einfachste Beispiel das Kern-get() {
      Rückgabequelle [Schlüssel];
    },
    setze(neuerWert) {
      wenn (neuerWert === Quelle[Schlüssel]) {
        zurückkehren;
      }
      Quelle[Schlüssel] = neuerWert;
    }
  });
}
// Durchlaufe die Attribute und mounte die Funktion proxyObj(target, source) {
  für (let-Schlüssel in Quelle) {
    // Die direkte Verwendung von obj.hasOwnProperty führt zu einem nicht standardmäßigen if (Object.prototype.hasOwnProperty.call(source, key)) {
      ProxyKey(Ziel, Quelle, Schlüssel);
    }
  }
}
let Optionen = {
  Daten: { Name: 1 }
};
ProxyObj(Optionen, Optionen.Daten);
// 1
konsole.log(Optionen.Name);

Übrigens sind die Grundprinzipien der Attribut-Entführung und des Mountens von Attributen in Vue fast dieselben wie oben.

defineProperty kann auch Protokolle schreiben

Beispielsweise hat obj ein Attribut, dessen Wert sich häufig ändert, und wir möchten alle seine geänderten Werte aufzeichnen, um ein Protokoll zu erstellen.

lass obj = { a: 1 };

lass log = [Objekt.a];

sei Wert = Objekt.a;
Objekt.defineProperty(obj, "a", {
  erhalten() {
    Rückgabewert;
  },
  setze(neuerWert) {
    wenn (neuerWert === Wert) {
      zurückkehren;
    }
    Wert = neuerWert;
    log.push(neuerWert);
  }
});

obj.a = 2;
obj.a = 3;
obj.a = 4;
// [1,2,3,4]
konsole.log(log);

Um die Änderungen eines bestimmten Wertes aufzuzeichnen, kann eine allgemeine Klasse extrahiert werden.

Klasse Archiver {
  Konstruktor() {
    lass Wert = null;
    dieses.archive = [];
    Objekt.defineProperty(dies, "a", {
      erhalten() {
        Rückgabewert;
      },
      setze(neuerWert) {
        wenn (neuerWert === Wert) {
          zurückkehren;
        }
        Wert = neuerWert;
        dies.archive.push(neuerWert);
      }
    });
  }
}
let Archiver = neuer Archiver();
Archivierer.a = 1;
Archivierer.a = 2;
// [1,2]
Konsole.log(Archivierer.Archiv);

Verweise

defineProperty von MDN

Zusammenfassen

Dies ist das Ende dieses Artikels über die Implementierung von Property Hijacking mit JavaScript defineProperty. Weitere verwandte Inhalte zum Property Hijacking von defineProperty finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

<<:  Ubuntu Docker-Installation in VMware (Containererstellung)

>>:  Mysql löst das N+1-Abfrageproblem der Datenbank

Artikel empfehlen

Detaillierte Erklärung zur Verwendung des <meta>-Tags in HTML

Wenn wir möchten, dass mehr Leute die von uns ers...

Zusammenfassung der MySQL-Zeitstatistikmethoden

Beim Erstellen von Datenbankstatistiken müssen Si...

Freigabe der schnellen Wiederherstellungslösung für große MySQL-SQL-Dateien

Vorwort Bei der Verwendung einer MySQL-Datenbank ...

Detaillierte Erklärung der Dreieckszeichnung und clevere Anwendungsbeispiele in CSS

führen Einige gängige Dreiecke auf Webseiten könn...

Mysql speichert Baumstruktur durch Adjazenzliste (Adjazenzliste)

Der folgende Inhalt stellt den Prozess und die Lö...

Detaillierte Erläuterung des Beispiels der Caching-Methode von Vue

Kürzlich wurde die neue Anforderung „Front-End-Ca...

So zeichnen Sie eine Schaltfläche in XAML als Kreis neu

Beim Verwenden des XAML-Layouts müssen manchmal ei...

Ergänzender Artikel zur Front-End-Performance-Optimierung

Vorwort Ich habe mir die zuvor veröffentlichten A...

Implementierung der HTML-Befehlszeilenschnittstelle

HTML-Teil Code kopieren Der Code lautet wie folgt:...