J'utilise Traceur Compiler pour tirer parti des fonctionnalités de l'ES6.
Je veux implémenter ce genre de choses depuis ES5:
function Animal() {
var self = this,
sayHi;
sayHi = function() {
self.hi();
};
this.hi = function() {/* ... */}
}
Actuellement, traceur ne prend pas en charge les mots-clés private
et public
( d'harmonie ). Et la syntaxe de classe ES6 ne permet pas d'utiliser des instructions simples var
(ou let
) dans le corps de la classe.
Le seul moyen que je trouve est de simuler des soldats avant la déclaration de classe. Quelque chose comme:
var sayHi = function() {
// ... do stuff
};
class Animal {
...
Il vaut mieux que rien, mais comme prévu, vous ne pouvez pas passer la bonne this
à une méthode privée sans apply
- ing ou bind
- à chaque fois.
Alors, est-il possible d'utiliser des données privées de classe ES6 compatibles avec le compilateur traceur?
Il n'y a pas de mots-clés private
, public
ou protected
dans la version actuelle spécification ECMAScript 6 .
Donc, Traceur ne supporte pas private
et public
. 6to5 (actuellement appelé "Babel") réalise cette proposition à des fins expérimentales (voir aussi cette discussion ). Mais ce n'est qu'une proposition, après tout.
Donc, pour l'instant, vous pouvez simplement simuler des propriétés privées via WeakMap
(voir ici ). Une autre alternative est Symbol
- mais elle ne fournit pas de confidentialité, car la propriété est facilement accessible via Object.getOwnPropertySymbols
.
IMHO la meilleure solution pour le moment - utilisez simplement la pseudo-confidentialité. Si vous utilisez fréquemment apply
ou call
avec votre méthode, cette méthode est très spécifique à un objet. Donc, ça vaut la peine de le déclarer dans votre classe juste avec le préfixe de soulignement:
class Animal {
_sayHi() {
// do stuff
}
}
Vous pouvez toujours utiliser les fonctions normales:
function myPrivateFunction() {
console.log("My property: " + this.prop);
}
class MyClass() {
constructor() {
this.prop = "myProp";
myPrivateFunction.bind(this)();
}
}
new MyClass(); // 'My property: myProp'
Bien qu’il n’existe actuellement aucun moyen de déclarer une méthode ou une propriété comme privée, les modules ES6 ne sont pas dans l’espace de noms global. Par conséquent, tout ce que vous déclarez dans votre module et que vous n'exportez pas ne sera disponible pour aucune autre partie de votre programme, mais sera toujours disponible pour votre module pendant l'exécution. Ainsi, vous avez des propriétés et des méthodes privées :)
Voici un exemple (dans le fichier test.js
])
function tryMe1(a) {
console.log(a + 2);
}
var tryMe2 = 1234;
class myModule {
tryMe3(a) {
console.log(a + 100);
}
getTryMe1(a) {
tryMe1(a);
}
getTryMe2() {
return tryMe2;
}
}
// Exports just myModule class. Not anything outside of it.
export default myModule;
Dans un autre fichier
import MyModule from './test';
let bar = new MyModule();
tryMe1(1); // ReferenceError: tryMe1 is not defined
tryMe2; // ReferenceError: tryMe2 is not defined
bar.tryMe1(1); // TypeError: bar.tryMe1 is not a function
bar.tryMe2; // undefined
bar.tryMe3(1); // 101
bar.getTryMe1(1); // 3
bar.getTryMe2(); // 1234
Vous pouvez utiliser le symbole
var say = Symbol()
function Cat(){
this[say]() // call private methos
}
Cat.prototype[say] = function(){ alert('im a private') }
P.S. alexpods n'est pas correct. il est protégé plutôt que privé, car l'héritage est un conflit de noms
En fait, vous pouvez utiliser var say = String(Math.random())
à la place de Symbol
EN ES6:
var say = Symbol()
class Cat {
constructor(){
this[say]() // call private
}
[say](){
alert('im private')
}
}
J'espère que cela peut être utile. :)
I. Déclarer vars, fonctions inside IIFE (expression de fonction invoquée immédiatement) , celles-ci ne peuvent être utilisées que dans la fonction anonyme. (Il peut être intéressant d’utiliser des mots-clés "let, const" sans utiliser "var" lorsque vous devez modifier le code de ES6.)
let Name = (function() {
const _privateHello = function() {
}
class Name {
constructor() {
}
publicMethod() {
_privateHello()
}
}
return Name;
})();
II. L'objet WeakMap peut être utile pour des problèmes de mémoire vive.
Les variables stockées dans WeakMap seront supprimées lorsque l'instance sera supprimée. Vérifiez cet article. ( Gestion des données privées des classes ES6 )
let Name = (function() {
const _privateName = new WeakMap();
})();
III. Mettons tout ensemble.
let Name = (function() {
const _privateName = new WeakMap();
const _privateHello = function(fullName) {
console.log("Hello, " + fullName);
}
class Name {
constructor(firstName, lastName) {
_privateName.set(this, {firstName: firstName, lastName: lastName});
}
static printName(name) {
let privateName = _privateName.get(name);
let _fullname = privateName.firstName + " " + privateName.lastName;
_privateHello(_fullname);
}
printName() {
let privateName = _privateName.get(this);
let _fullname = privateName.firstName + " " + privateName.lastName;
_privateHello(_fullname);
}
}
return Name;
})();
var aMan = new Name("JH", "Son");
aMan.printName(); // "Hello, JH Son"
Name.printName(aMan); // "Hello, JH Son"
Comme le dit alexpods, il n’existe aucun moyen de le faire dans ES6. Cependant, pour ceux que cela intéresse, il existe également une proposition pour opérateur de liaison qui permet ce type de syntaxe:
function privateMethod() {
return `Hello ${this.name}`;
}
export class Animal {
constructor(name) {
this.name = name;
}
publicMethod() {
this::privateMethod();
}
}
Encore une fois, il ne s'agit que d'une proposition. Votre kilométrage peut varier.
Avez-vous envisagé d'utiliser les fonctions d'usine? Ils sont généralement un bien meilleure alternative aux classes ou aux fonctions constructeurs en Javascript. Voici un exemple de la façon dont cela fonctionne:
function car () {
var privateVariable = 4
function privateFunction () {}
return {
color: 'red',
drive: function (miles) {},
stop: function() {}
....
}
}
Grâce aux fermetures, vous avez accès à toutes les fonctions et variabels privées à l'intérieur de l'objet renvoyé, mais vous ne pouvez pas y accéder de l'extérieur.
Comme Marcelo Lazaroni a déjà dit,
Bien qu’il n’existe actuellement aucun moyen de déclarer une méthode ou une propriété comme étant privée, les modules ES6 ne figurent pas dans l’espace de noms global. Par conséquent, tout ce que vous déclarez dans votre module et que vous n'exportez pas ne sera disponible pour aucune autre partie de votre programme, mais le sera toujours pendant l'exécution.
Mais son exemple n'a pas montré comment la méthode privée pouvait accéder aux membres de l'instance de la classe. Max nous montre quelques bons exemples de la manière dont les membres de l'instance d'accès via une liaison ou l'utilisation alternative d'une méthode lambda dans le constructeur, mais j'aimerais ajouter un moyen plus simple de le faire: passer l'instance en tant que un paramètre à la méthode privée. En procédant ainsi, la classe MyClass de Max ressemblerait à ceci:
function myPrivateFunction(myClass) {
console.log("My property: " + myClass.prop);
}
class MyClass() {
constructor() {
this.prop = "myProp";
}
testMethod() {
myPrivateFunction(this);
}
}
module.exports = MyClass;
La façon dont vous le faites dépend vraiment de vos préférences personnelles.
Je suis venu avec ce que je pense est une solution bien meilleure permettant:
pas besoin de 'this._', that/self, cartes faibles, symboles, etc. Code 'classe' clair et simple
les variables et méthodes privées sont vraiment privées et ont le bon lien 'this'
Aucune utilisation de 'this', ce qui signifie un code clair beaucoup moins sujet aux erreurs
l'interface publique est claire et séparée de l'implémentation en tant que proxy pour les méthodes privées
permet une composition facile
avec cela vous pouvez faire:
function Counter() {
// public interface
const proxy = {
advance, // advance counter and get new value
reset, // reset value
value // get value
}
// private variables and methods
let count=0;
function advance() {
return ++count;
}
function reset(newCount) {
count=(newCount || 0);
}
function value() {
return count;
}
return proxy;
}
let counter=Counter.New();
console.log(counter instanceof Counter); // true
counter.reset(100);
console.log('Counter next = '+counter.advance()); // 101
console.log(Object.getOwnPropertyNames(counter)); // ["advance", "reset", "value"]
<script src="https://cdn.rawgit.com/kofifus/New/7987670c/new.js"></script>
voir Nouvea pour le code et des exemples plus élaborés, y compris constructeur et composition