Wann verwenden Sie Object.defineProperty()

Lesezeit: 7 Minuten

Benutzer-Avatar
André Meinhold

Ich frage mich, wann ich es verwenden sollte

Object.defineProperty

um neue Eigenschaften für ein Objekt zu erstellen. Ich bin mir bewusst, dass ich Dinge wie einstellen kann

enumerable: false

aber wann braucht man das wirklich? Wenn Sie nur eine Eigenschaft wie festlegen

myObject.myprop = 5;

seine Deskriptoren sind alle auf true gesetzt, richtig? Ich bin eigentlich eher neugierig, wann Sie diesen ziemlich ausführlichen Aufruf von .defineProperty() verwenden und aus welchen Gründen.

Benutzer-Avatar
Rob W

Object.defineProperty wird hauptsächlich verwendet, um Eigenschaften mit bestimmten Eigenschaftsdeskriptoren festzulegen (z. B. schreibgeschützt (Konstanten), Aufzählbarkeit (um eine Eigenschaft in einer for (.. in ..) Schleife, Getter, Setter).

"use strict";
var myObj = {}; // Create object
// Set property (+descriptor)
Object.defineProperty(myObj, 'myprop', {
    value: 5,
    writable: false
});
console.log(myObj.myprop);// 5
myObj.myprop = 1;         // In strict mode: TypeError: myObj.myprop is read-only

Beispiel

Diese Methode erweitert die Object Prototyp mit einer Eigenschaft. Nur der Getter ist definiert und die Aufzählbarkeit ist auf gesetzt false.

Object.defineProperty(Object.prototype, '__CLASS__', {
    get: function() {
        return Object.prototype.toString.call(this);
    },
    enumerable: false // = Default
});
Object.keys({});           // []
console.log([].__CLASS__); // "[object Array]"

  • OK das verstehe ich. Aber ist das sinnvoll? Meistens möchte ich, dass alle Deskriptoren auf wahr gesetzt sind, damit ich die Eigenschaften einfach auf die altmodische Weise einrichten kann, oder? Gibt es noch andere Vorteile für .defineProperty?

    – André Meinhold

    11. April 2012 um 12:29 Uhr

  • @RobW: Sie können auch erstellen getters und setters ohne zu benutzen .defineProperty.

    – jAndy

    11. April 2012 um 12:40 Uhr

  • @jAndy Aber die Eigenschaft wird in a angezeigt for (.. in ..) Schleife: Object.prototype.__defineGetter__('lol',function(){return 3});for(var i in [])alert(i); zeigt an "lol". Object.defineProperty kann verwendet werden, um einen Getter/Setter zu definieren, der Auch tut nicht zeige dich ein for (.. in ..) Schleifen.

    – Rob W

    11. April 2012 um 12:45 Uhr

  • @RobW: Ich habe mehr über die Verwendung nachgedacht var foo = { get lol() { return 5;} };aber das Problem bleibt das gleiche.

    – jAndy

    11. April 2012 um 12:48 Uhr

  • @Andre: Wenn du keinen Anwendungsfall für sie siehst, dann brauchst du sie nicht … wenn du sie brauchst, wirst du es wissen 😉

    – Felix Klinge

    11. April 2012 um 12:56 Uhr

Benutzer-Avatar
Pascalius

Features wie ‘enumerable’ werden meiner Erfahrung nach selten genutzt. Der Hauptanwendungsfall sind berechnete Eigenschaften:

var myObj = {};

myObj.width = 20;
myObj.height = 20;

Object.defineProperty(myObj, 'area', {
    get: function() {
        return this.width*this.height;
    }
});
console.log(myObj.area);

  • Es scheint mir, als würden Sie sich alle Mühe geben, dies im Namen einer sehr grauen Zone in der Semantik zu einer Eigenschaft zu machen.

    – aaaaa

    12. Januar 2015 um 14:49 Uhr

  • @aaaaa was? graue Zone?

    – Pascalius

    12. Januar 2015 um 14:57 Uhr

  • Ich verstehe einfach nicht den Anwendungsfall, eine berechnete Eigenschaft bereitzustellen, anstatt sie einfach zu einer Funktion zu machen. zB myObj.area = function() { return this.width * this.height; }

    – aaaaa

    12. Januar 2015 um 22:46 Uhr


  • Die Funktion ist vollständig gültig, aber es kann Anwendungsfälle geben, in denen Sie eine Eigenschaft einer Funktion vorziehen.

    – Pascalius

    13. Januar 2015 um 10:26 Uhr

  • Die primäre Verwendung wäre, dass Sie, anstatt zwei separate Funktionen (z. B.: getFoo(), setFoo()) zu haben, eine einzelne Eigenschaft mit einem Getter / Setter definieren können, der benutzerdefinierte Logik umschließt, und dann einfach Standardzuweisungsoperatoren für eine einzelne verwenden können Mitglied (z. B. x = myObj.Foo oder myObj.Foo = x). Dies macht Ihren Code einfacher und ist auch nützlich, wenn Sie verhindern möchten, dass beim Serialisieren in JSON ein Wert ausgegeben wird. (z. B.: Ihr Objekt hat eine Reihe von UI-spezifischen Eigenschaften, die Sie nicht über die Leitung senden möchten …) Alles in allem hilft dies JS dabei, den Standard-OO-Prinzipien besser zu folgen

    – Joshua Barker

    29. Juli 2015 um 22:28 Uhr


Ein wirklich guter Grund für die Verwendung von Object.defineProperty ist, dass Sie damit eine Funktion in einem Objekt als berechnete Eigenschaft durchlaufen können, die die Funktion ausführt, anstatt den Hauptteil der Funktion zurückzugeben.

Zum Beispiel:

var myObj = {};

myObj.width = 20;
myObj.height = 20;

Object.defineProperty(myObj, 'area', {
    get: function() {
        return this.width*this.height;
    },
    enumerable: true
});

for (var key in myObj) {
  if (myObj.hasOwnProperty(key)) {
    console.log(key + " -> " + myObj[key]);
  }
}
//width -> 20, height -> 20, area -> 400

Im Gegensatz zum Hinzufügen der Funktion als Eigenschaft zu einem Objektliteral:

var myObj = {};

myObj.width = 20;
myObj.height = 20;

myObj.area = function() {
       return this.width*this.height;
    };

for (var key in myObj) {
  if (myObj.hasOwnProperty(key)) {
    console.log(key + " -> " + myObj[key]);
  }
}
// width -> 20, height -> 20, area -> function() { return this.width*this.height;}

Stellen Sie sicher, dass Sie die Enumerable-Eigenschaft auf true setzen, um sie zu durchlaufen.

Benutzer-Avatar
Danziger

Zum Beispiel, so verfolgt Vue.js Änderungen in der data Objekt:

Wenn Sie ein einfaches JavaScript-Objekt an eine Vue-Instanz als its data Option durchläuft Vue alle seine Eigenschaften und konvertiert sie in getter/setters verwenden Object.defineProperty. Dies ist eine Funktion nur für ES5 und nicht shimmbar, weshalb Vue IE8 und darunter nicht unterstützt.

Die Getter/Setter sind für den Benutzer unsichtbar, aber unter der Haube ermöglichen sie Vue, eine Abhängigkeitsverfolgung und Änderungsbenachrichtigung durchzuführen, wenn auf Eigenschaften zugegriffen oder diese geändert werden.

[…]

Denken Sie daran, dass selbst eine superschlanke und einfache Version von Vue.js etwas mehr als nur verwenden würde Object.definePropertyaber die Hauptfunktionalität kommt davon:

Der Reaktivitätszyklus von Vue.js

Hier sehen Sie einen Artikel, in dem der Autor eine minimale PoC-Version von so etwas wie Vue.js implementiert: https://medium.com/js-dojo/understand-vue-reactivity-implementation-step-by-step-599c3d51cd6c

Und hier ein Vortrag (auf Spanisch), in dem der Sprecher etwas Ähnliches aufbaut, während er die Reaktivität in Vue.js erklärt: https://www.youtube.com/watch?v=axXwWU-L7RM

Zusammenfassung:

In Javascript sind Objekte Sammlungen von Schlüssel-Wert-Paaren.
Object.defineProperty() ist eine Funktion, die eine neue Eigenschaft für ein Objekt definieren und die folgenden Attribute einer Eigenschaft festlegen kann:

  • Wert <any>: Der dem Schlüssel zugeordnete Wert
  • schreibbar <boolean>: wenn beschreibbar eingestellt ist true Die Eigenschaft kann aktualisiert werden, indem ihr ein neuer Wert zugewiesen wird. Wenn eingestellt false Sie können den Wert nicht ändern.
  • aufzählbar <boolean>: wenn enumerable auf gesetzt ist true Auf das Eigentum kann über a zugegriffen werden for..in Schleife. Weiterhin werden nur die aufzählbaren Eigenschaftsschlüssel mit zurückgegeben Object.keys()
  • konfigurierbar <boolean>: Wenn konfigurierbar auf eingestellt ist false Sie können die Eigenschaftsattribute (Wert/beschreibbar/aufzählbar/konfigurierbar) nicht ändern, auch da Sie den Wert nicht ändern können, können Sie ihn nicht mit löschen delete Operator.

Beispiel:

let obj = {};


Object.defineProperty(obj, 'prop1', {
      value: 1,
      writable: false,
      enumerable: false,
      configurable: false
});   // create a new property (key=prop1, value=1)


Object.defineProperty(obj, 'prop2', {
      value: 2,
      writable: true,
      enumerable: true,
      configurable: true
});  // create a new property (key=prop2, value=2)


console.log(obj.prop1, obj.prop2); // both props exists

for(const props in obj) {
  console.log(props);
  // only logs prop2 because writable is true in prop2 and false in prop1
}


obj.prop1 = 100;
obj.prop2 = 100;
console.log(obj.prop1, obj.prop2);
// only prop2 is changed because prop2 is writable, prop1 is not


delete obj.prop1;
delete obj.prop2;

console.log(obj.prop1, obj.prop2);
// only prop2 is deleted because prop2 is configurable and prop1 is not

Benutzer-Avatar
Tim Ogilvy

Object.defineProperty verhindert, dass Sie versehentlich einem Schlüssel in seiner Prototypkette Werte zuweisen. Mit dieser Methode weisen Sie nur dieser bestimmten Objektebene zu (nicht irgendeinem Schlüssel in der Prototypenkette).

Zum Beispiel: Es gibt ein Objekt wie {key1: value1, key2: value2} und Sie kennen die Prototypkette nicht genau oder Sie verpassen sie versehentlich und es gibt irgendwo in der Prototypkette eine Eigenschaft “Farbe”.

Verwendung von Punkt (.) Zuweisung-

Diese Operation weist dem Schlüssel „Farbe“ in der Prototypkette einen Wert zu(falls Schlüssel irgendwo vorhanden) und Sie finden das Objekt unverändert als . obj.color=”blau”; // obj bleibt dasselbe wie {key1: value1, key2: value2}

mit der Object.defineProperty-Methode

Object.defineProperty(obj, 'color', {
  value: 'blue'
});

// jetzt sieht obj aus wie {key1: value1, key2: value2, color: 'blue'}. Es fügt der gleichen Ebene eine Eigenschaft hinzu. Dann können Sie sicher mit der Methode iterieren Object.hasOwnProperty().

Ein netter Anwendungsfall, den ich gesehen habe defineProperty ist für Bibliotheken, dem Benutzer eine Fehlereigenschaft bereitzustellen, auf die Sie den Fehler selbst protokollieren würden, wenn nicht innerhalb eines bestimmten Intervalls darauf zugegriffen wird. Zum Beispiel:

let logErrorTimeoutId = setTimeout(() => {
  if (error) {
    console.error('Unhandled (in <your library>)', error.stack || error);
  }
}, 10);

Object.defineProperty(data, 'error', {
    configurable: true,
    enumerable: true,
    get: () => {
      clearTimeout(logErrorTimeoutId);
      return error;
    },
  });

Quelle für diesen Code: https://github.com/apollographql/react-apollo/blob/ddd3d8faabf135dca691d20ce8ab0bc24ccc414e/src/graphql.tsx#L510

1068990cookie-checkWann verwenden Sie Object.defineProperty()

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy