web-dev-qa-db-fra.com

Comment déclarer des variables privées et des méthodes privées dans la classe es6

dans es5 nous utilisons la fonction constructeur  

function Person(name,gender){

    var initial ="";    // we use var key Word to make variable private

    function getNameWithInitial(){ // this is the private method to get name with initial
        console.log(this);
        initial = this.gender ==="male"?"Mr. ":"Mrs. ";
        return initial + this.name;
    }


    this.name = name;
    this.gender = gender;
    this.getName = function(){
        return getNameWithInitial.call(this);
    }


}


var manas = new Person("Manas","male");

console.log(manas.getName());

Ma question est de savoir comment déclarer une variable privée et une méthode privée dans la classe es6

14
manas

Un moyen d'y parvenir consiste à utiliser une autre fonction ES2015 appelée modules

Vous connaissez peut-être déjà les modules AMD ou les modules commonJS (utilisés par Nodejs). Eh bien ES6/ES2015 apporte une norme pour JS - nous les appellerons modules ES6 mais ils font maintenant partie du langage JS. Une fois que vous avez des modules, vous avez la possibilité de cacher des informations à la fois pour les fonctions privées et les variables d’objet. Gardez à l'esprit que seul ce que vous "exportez" est visible pour le code d'appel du client.

Permet de travailler à travers votre exemple de code. Voici une première coupe:

person.js

 const getNameWithInitial = function () {
      let initial = this._gender === 'male' ?
      'Mr. ' :
      'Mrs. ';
      return initial + this._name;
    }

  export class Person {

    constructor(name, gender) {
        this._name = name;
        this._gender = gender;
      }

      get name() {
          return getNameWithInitial.call(this);
        }
    }
  }

client.js

import {Person} from './person';
const manas = new Person('Manas', 'male');
console.log(manas.name);  // this calls what was your getName function

Désormais, la fonction getNameWithInitial est en réalité privée, car elle n'est pas exportée. Par conséquent, client.js ne peut pas la voir.

Cependant, nous avons toujours un problème pour la classe Person, puisque celle-ci est exportée. Pour le moment, vous pouvez simplement vous approcher de l'objet Manas et faire:

manas._name = 'Joe'

Avec des propriétés comme _name, nous pouvons combiner des modules et symboles . Il s'agit d'une technique de masquage d'informations puissante mais légère, disponible avec ES6 +/ES2015.

Symbol est un nouveau type intégré. Chaque nouvelle valeur de symbole est unique. Par conséquent, peut être utilisé comme clé sur un objet.

Si le code appelant du client ne connaît pas le symbole utilisé pour accéder à cette touche, il ne peut pas le récupérer car le symbole n'est pas exporté.

Voyons notre code modifié pour utiliser des symboles et des modules pour masquer les attributs de classe.

person.js

const s_name = Symbol();
const s_gender = Symbol();

const getNameWithInitial = function () {
  let initial = this[s_gender] === 'male' ?
    'Mr. ' :
    'Mrs. ';
  return initial + this[s_name];
}

export class Person {

  constructor(name, gender) {
    this[s_name] = name;
    this[s_gender] = gender;
  }

  get name() {
    return getNameWithInitial.call(this);
  }
}

Donc, maintenant, un client ne peut pas simplement faire:

 manas._name = 'Joe' 

parce que _name n'est pas utilisé comme clé pour la valeur du nom.

Cependant, les symboles sont exposés via des fonctions de réflexion telles que Object.getOwnPropertySymbols, alors soyez conscient qu'ils ne sont pas "complètement" privés si vous utilisez cette technique.

import {Person} from './person';
const manas = new Person('Manas', 'male');
const vals = Object.getOwnPropertySymbols(manas);
manas[vals[0]] = 'Joanne';
manas[vals[1]] = 'female';

Message à emporter - Les modules en général sont un excellent moyen de cacher quelque chose, car s'ils ne sont pas exportés, ils ne peuvent pas être utilisés en dehors du module et utilisés avec des symboles stockés de manière privée pour servir de clés. ). L'utilisation de modules aujourd'hui est disponible avec des outils de construction, par exemple. webpack/browserify et babel.

18
arcseldon

Si vous souhaitez un analogue à la solution ES5, c'est très simple. la constructor devient simplement ce qui retient la fermeture, et vous ajoutez toutes les méthodes/objets qui doivent se rappeler de l'état privé qui s'y trouve.
Les méthodes prototypées n’ont pas accès à la fermeture du constructeur initial, sans utiliser certains getters privilégiés:

class Person {

  constructor ({ name, age, deepDarkSecret }) {
    const bribe = () => console.log(`Give me money, or everybody will know about ${ redactRandom(deepDarkSecret) }`);

    Object.assign(this, { name, age }); // assigning publicly accessible values
    Object.assign(this, { bribe }); // assign "privileged" methods (functions with closure-reference to initial values)
  }

  recallSecret () {
    console.log("I'm just a prototyped method, so I know nothing about any secret, unless I use a privileged function...");
    this.bribe();
  }
}

Si vous regardez ce que cela vous rapporte, vous remarquerez que ce n'est vraiment pas très différent de votre exemple (en utilisant simplement des cloches et des sifflets "plus propres"; surtout lorsque vous ajoutez des méthodes prototype/statique). C'est toujours le prototype en dessous.

Si vous avez le luxe d'utiliser n'importe quel type de module/export (ES6 étant l'idéal), alors avec un autre type de données,vous pouvez avoir une vraie confidentialité et ne pas avoir à nettoyer après vous-même.

C'est un peu hackey. Cela deviendra probablement moins laid et, espérons-le, servira de base à quelque chose de plus propre à l'avenir, mais si vous souhaitez un accès privé basé sur une instance, même pour les méthodes prototypées, créez une WeakMapà l'intérieur du module. à partir de laquelle vous exportez votre classe.

Utilisez this comme clé . Plutôt que de créer des fonctions privilégiées avec un accès de fermeture, toutes les méthodes prototypes ont désormais un accès de fermeture au faiblesse.
... L’inconvénient est que chaque fois que vous voulez des variables privées, vous devez les rechercher dans la variable WeakMap au lieu de les extraire de/à partir de this.

const personalBaggage = new WeakMap();

class Person {
  constructor ({ name, age, darkestMoment }) {
    const privates = { name, age, darkestMoment };
    personalBaggage.add(this, privates);
  }

  recallDarkestHour () {
    const { darkestMoment } = personalBaggage.get(this);
    console.log(darkestMoment);
  }
}

export default Person;

Tant que vous ne perdez pas la référence dans this, cela devrait fonctionner.
Contrairement à l'utilisation de Symbol, vous ne pouvez pas obtenir une référence à l'objet privé, peu importe les efforts que vous déployez.
Si vous connaissez les symboles sur l'objet, vous pouvez rechercher les propriétés à l'aide de ces symboles.
Et obtenir la liste des symboles sur n’importe quel objet n’est qu’un appel de fonction loin de là Symboln’est pas de garder les choses privées; il s'agit de protéger les objets des collisions de noms et de définir des symboles communs qui peuvent être utilisés sur n'importe quel objet/fonction, mais ne seront pas capturés dans des boucles, ne seront pas appelés ou écrasés accidentellement, et cetera.

Le stockage du sac privé de données dans une carte faible avec this comme clé vous donne accès à un jeu de données complètement caché, totalement inaccessible en dehors de ce module.
Quoi de mieux, la clé/valeur dans les cartes faibles n'empêche pas le CPG de les nettoyer.
Normalement, s’ils restaient dans un tableau, ils y resteraient. Si le dernier emplacement utilisé par un objet est la clé dans une carte faible, il est alors collecté et la valeur de la carte faible est automatiquement effacée (dans l'ES6 natif; les bonus de mémoire ne peuvent pas être remplis, mais l'objet peut).

5
Norguard

voici un très bon post sur le sujet. Je ne savais pas grand chose à propos de faire cela dans ES6 avant votre question, mais après avoir examiné cela, cela semble vraiment cool. Vous créez donc un symbole indexé à la fonction. 

voici le code directement de leur sit.

var Person = (function() {
    var nameSymbol = Symbol('name');

    function Person(name) {
        this[nameSymbol] = name;
    }

    Person.prototype.getName = function() {
        return this[nameSymbol];
    };

    return Person;
}());

var p = new Person('John');

Propriétés privées en JavaScript

0
andre mcgruder

Vous pouvez le faire en utilisant Symbol.

const _name = Symbol();

class Person {
  constructor(name) {
    this[_name] = name;
  } 
}

const person = new Person('John');

alert(person.name);
// => undefined

0
jlowgren