javascript - Cómo implementar un método privado en una clase ES6 con Traceur
Uso el compilador Traceur para tener ventaja con las características de ES6 ahora.
Quiero implementar estas cosas de ES5:
function Animal() {
var self = this,
sayHi;
sayHi = function() {
self.hi();
};
this.hi = function() {/* ... */}
}
Actualmente traceur no soporta las palabras clave private y public (de harmony). Y la sintaxis de clases de ES6 no permite usar declaraciones simples de var (o let) en el cuerpo de la clase.
La única forma que encuentro es simular privados antes de la declaración de la clase. Algo como:
var sayHi = function() {
// ... do stuff
};
class Animal {
...
Es mejor que nada, pero como era de esperar, no puedes pasar correctamente this a un método privado sin apply o bind cada vez.
Entonces, ¿hay alguna posibilidad de usar datos privados en una clase ES6 compatible con el compilador traceur?
Respuesta #1
No hay palabras clave private, public o protected en la especificación actual de ECMAScript 6.
Así que Traceur no soporta private y public. 6to5 (actualmente se llama "Babel") realiza esta propuesta con fines experimentales (ver también esta discusión). Pero, después de todo, es solo una propuesta.
Así que por ahora puedes simplemente simular propiedades privadas mediante WeakMap (ver aquí). Otra alternativa es Symbol, pero no proporciona verdadera privacidad ya que la propiedad puede ser fácilmente accesible mediante Object.getOwnPropertySymbols.
En mi humilde opinión, la mejor solución en este momento es simplemente usar pseudo privacidad. Si usas frecuentemente apply o call con tu método, entonces este método es muy específico del objeto. Por lo tanto, vale la pena declararlo en tu clase solo con un prefijo de guion bajo:
class Animal {
_sayHi() {
// do stuff
}
}
Respuesta #2
Siempre puedes usar funciones normales:
function myPrivateFunction() {
console.log("My property: " + this.prop);
}
class MyClass() {
constructor() {
this.prop = "myProp";
myPrivateFunction.bind(this)();
}
}
new MyClass(); // 'My property: myProp'
Respuesta #3
Aunque actualmente no hay forma de declarar un método o propiedad como privado, los módulos ES6 no están en el espacio de nombres global. Por lo tanto, cualquier cosa que declares en tu módulo y no exportes no estará disponible para ninguna otra parte de tu programa, pero seguirá estando disponible para tu módulo durante la ejecución. Así, tienes propiedades y métodos privados :)
Aquí hay un ejemplo (en el archivo 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;
En otro archivo
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
Respuesta #4
Puedes usar Símbolo
var say = Symbol()
function Cat(){
this[say]() // call private methos
}
Cat.prototype[say] = function(){ alert('im a private') }
P.D. alexpods no está correcto. él obtiene protegido en lugar de privado, ya que la herencia es un conflicto de nombres
En realidad, puedes usar var say=String(Math.random()) en lugar de Symbol
EN ES6:
var say = Symbol()
class Cat {
constructor(){
this[say]() // call private
}
[say](){
alert('im private')
}
}
Respuesta #5
Espero que esto pueda ser útil. :)
I. Declarar variables y funciones dentro de un IIFE (expresión de función invocada inmediatamente), esas solo pueden ser usadas en la función anónima. (Puede ser bueno usar las palabras clave "let, const" sin usar 'var' cuando necesites cambiar el código para ES6.)
let Name = (function() {
const _privateHello = function() {
}
class Name {
constructor() {
}
publicMethod() {
_privateHello()
}
}
return Name;
})();
II. El objeto WeakMap puede ser bueno para problemas de fugas de memoria.
Las variables almacenadas en el WeakMap se eliminarán cuando la instancia sea eliminada. Consulta este artículo. (Gestión de los datos privados de las clases ES6)
let Name = (function() {
const _privateName = new WeakMap();
})();
III. Vamos a poner todo junto.
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"
Respuesta #6
¿Has considerado usar funciones fábrica? Por lo general, son una alternativa mucho mejor a las clases o funciones constructoras en Javascript. Aquí hay un ejemplo de cómo funciona:
function car () {
var privateVariable = 4
function privateFunction () {}
return {
color: 'red',
drive: function (miles) {},
stop: function() {}
....
}
}
Gracias a los closures, tienes acceso a todas las funciones y variables privadas dentro del objeto devuelto, pero no puedes acceder a ellas desde afuera.
Respuesta #7
Como dice alexpods, no hay una forma dedicada de hacer esto en ES6. Sin embargo, para aquellos interesados, también hay una propuesta para el operador bind que permite este tipo de sintaxis:
function privateMethod() {
return `Hello ${this.name}`;
}
export class Animal {
constructor(name) {
this.name = name;
}
publicMethod() {
this::privateMethod();
}
}
Una vez más, esto es solo una propuesta. Tu experiencia puede variar.
