web-dev-qa-db-fra.com

Retour du proxy ES6 à partir du constructeur de classe ES6

Je veux que l'utilisateur définisse uniquement des propriétés spécifiques pour un objet, mais en même temps, cet objet doit être construit à partir d'une classe personnalisée.

Par exemple

var row = new Row({
  name : 'John Doe',
  email : '[email protected]'
}, Schema);

row peut avoir des méthodes. Mais lorsque l'utilisateur essaie de définir row.password, ils ne sont pas autorisés.

Une façon de le faire est d'utiliser new Proxy au lieu de new Row mais nous perdrons toutes les choses intéressantes que nous faisons dans la classe Row. Je voudrais new Row pour renvoyer un objet proxy avec la référence this comme cible du proxy.

Quelqu'un a des idées à ce sujet? Si vous connaissez mongoose, comment mongoose procède-t-il?

17
Uday Hiwarale

Si le proxy est certain de se produire pour vous, une solution possible pour limiter la fonctionnalité définie consiste à renvoyer une instance de proxy ES6.

Par défaut, le constructeur en javascript renvoie automatiquement l'objet this mais vous pouvez définir et renvoyer un comportement personnalisé en instanciant un proxy sur this comme cible. Gardez à l'esprit que la méthode set dans le proxy doit renvoyer une valeur booléenne.

MDN : La méthode set doit renvoyer une valeur booléenne. Renvoyez true pour indiquer que l'affectation a réussi. Si la méthode set retourne false et que l'affectation s'est produite en code strict, une TypeError sera levée.

class Row {
  constructor(entry) {
    // some stuff

    return new Proxy(this, {
      set(target, name, value) {
        let setables = ['name', 'email'];
        if (!setables.includes(name)) {
          throw new Error(`Cannot set the ${name} property`);
        } else {
          target[name] = value;
          return true;
        }
      }
    });
  }

  get name() {
    return this._name;
  }
  set name(name) {
    this._name = name.trim();
  }
  get email() {
    return this._email;
  }
  set email(email) {
    this._email = email.trim();
  }
}

Donc, maintenant, vous n'êtes pas autorisé à définir les propriétés non paramétrables en fonction du proxy.

let row = new Row({
  name : 'John Doe',
  email : '[email protected]'
});

row.password = 'blahblahblah'; // Error: Cannot set the password property

Il est également possible d'avoir un comportement personnalisé sur la méthode get également.

Cependant, méfiez-vous et prenez soin de remplacer la référence renvoyée au contexte d'appel.

Remarque: L'exemple de code a été testé sur Node v8.1.3 et navigateurs modernes.

22
Vahid Hallaji

Vous pouvez le faire sans utiliser de procurations du tout.

Dans votre constructeur de classe, vous pouvez définir la propriété de mot de passe comme ceci:

constructor(options, schema) {
    this.name = options.name;
    this.email = options.email;
    Object.defineProperty(this, 'password', {
        configurable: false, // no re-configuring this.password
        enumerable: true, // this.password should show up in Object.keys(this)
        value: options.password, // set the value to options.password
        writable: false // no changing the value with this.password = ...
    });
    // whatever else you want to do with the Schema
}

Vous pouvez trouver plus d'informations sur la façon de l'utiliser sur la page Object.defineProperty() du MDN.

12
Joshua Skrzypek